From fb08487608f0276c1b71dd848deeb86dec9230bb Mon Sep 17 00:00:00 2001 From: shahoian Date: Thu, 11 Dec 2025 13:53:33 +0100 Subject: [PATCH 001/234] Demote warning to debug level --- Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx b/Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx index 34643928db344..691d731503b88 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx @@ -404,7 +404,7 @@ bool CheckResidSpec::processITSTrack(const o2::its::TrackITS& iTrack, const o2:: innerDone = true; } } else { - LOGP(warn, "No cluster on lr {}", i); + LOGP(debug, "No cluster on lr {}", i); } } } From 1c3bfa0d941dcdf6983173280d33cb1c2ad9cef4 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 3 Dec 2025 21:06:04 +0100 Subject: [PATCH 002/234] GPU QA: Add pad row vs occuapncy histogram --- GPU/GPUTracking/qa/GPUQA.cxx | 68 +++++++++++++++++++++++------------- GPU/GPUTracking/qa/GPUQA.h | 6 ++-- 2 files changed, 47 insertions(+), 27 deletions(-) diff --git a/GPU/GPUTracking/qa/GPUQA.cxx b/GPU/GPUTracking/qa/GPUQA.cxx index 689dc20cb1606..28b603f77e2ff 100644 --- a/GPU/GPUTracking/qa/GPUQA.cxx +++ b/GPU/GPUTracking/qa/GPUQA.cxx @@ -152,6 +152,7 @@ static constexpr float PT_MIN_CLUST = 0.01; static constexpr float PT_MAX = 20; static constexpr float ETA_MAX = 1.5; static constexpr float ETA_MAX2 = 0.9; +static constexpr int32_t PADROW_CHECK_MINCLS = 50; static constexpr bool CLUST_HIST_INT_SUM = false; @@ -525,9 +526,10 @@ int32_t GPUQA::InitQACreateHistograms() createHist(mClusters[i], name, name, AXIS_BINS[4], binsPt.get()); } - createHist(mPadRow[0], "padrow0", "padrow0", GPUCA_ROW_COUNT, 0, GPUCA_ROW_COUNT - 1, GPUCA_ROW_COUNT, 0, GPUCA_ROW_COUNT - 1); - createHist(mPadRow[1], "padrow1", "padrow1", 100.f, -0.2f, 0.2f, GPUCA_ROW_COUNT, 0, GPUCA_ROW_COUNT - 1); - createHist(mPadRow[2], "padrow2", "padrow2", 100.f, -0.2f, 0.2f, GPUCA_ROW_COUNT, 0, GPUCA_ROW_COUNT - 1); + createHist(mPadRow[0], "padrow0", "padrow0", GPUCA_ROW_COUNT - PADROW_CHECK_MINCLS, 0, GPUCA_ROW_COUNT - 1 - PADROW_CHECK_MINCLS, GPUCA_ROW_COUNT - PADROW_CHECK_MINCLS, 0, GPUCA_ROW_COUNT - 1 - PADROW_CHECK_MINCLS); + createHist(mPadRow[1], "padrow1", "padrow1", 100.f, -0.2f, 0.2f, GPUCA_ROW_COUNT - PADROW_CHECK_MINCLS, 0, GPUCA_ROW_COUNT - 1 - PADROW_CHECK_MINCLS); + createHist(mPadRow[2], "padrow2", "padrow2", 100.f, -0.2f, 0.2f, GPUCA_ROW_COUNT - PADROW_CHECK_MINCLS, 0, GPUCA_ROW_COUNT - 1 - PADROW_CHECK_MINCLS); + createHist(mPadRow[3], "padrow3", "padrow3", 100.f, 0, 300000, GPUCA_ROW_COUNT - PADROW_CHECK_MINCLS, 0, GPUCA_ROW_COUNT - 1 - PADROW_CHECK_MINCLS); } if (mQATasks & taskTrackStatistics) { @@ -968,7 +970,7 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx nClusters++; uint32_t hitId = mTracking->mIOPtrs.mergedTrackHits[track.FirstClusterRef() + k].num; if (hitId >= GetNMCLabels()) { - GPUError("Invalid hit id %u > %d (nClusters %d)", hitId, GetNMCLabels(), mTracking->mIOPtrs.clustersNative ? mTracking->mIOPtrs.clustersNative->nClustersTotal : 0); + GPUError("Invalid hit id %u > %d (nClusters %d)", hitId, GetNMCLabels(), clNative ? clNative->nClustersTotal : 0); throw std::runtime_error("qa error"); } acc.addLabel(hitId); @@ -1069,7 +1071,7 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx } } } - if ((mQATasks & taskClusterAttach)) { + if ((mQATasks & taskClusterAttach) && !tracksExternal) { std::vector lowestPadRow(mTracking->mIOPtrs.nMergedTracks); // fill cluster adjacent status if (mTracking->mIOPtrs.mergedTrackHitAttachment) { @@ -1096,12 +1098,12 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx } } } - if (mTracking->mIOPtrs.nMergedTracks && mTracking->mIOPtrs.clustersNative) { + if (mTracking->mIOPtrs.nMergedTracks && clNative) { std::fill(lowestPadRow.begin(), lowestPadRow.end(), 255); for (uint32_t iSector = 0; iSector < GPUCA_NSECTORS; iSector++) { for (uint32_t iRow = 0; iRow < GPUCA_ROW_COUNT; iRow++) { - for (uint32_t iCl = 0; iCl < mTracking->mIOPtrs.clustersNative->nClusters[iSector][iRow]; iCl++) { - int32_t i = mTracking->mIOPtrs.clustersNative->clusterOffset[iSector][iRow] + iCl; + for (uint32_t iCl = 0; iCl < clNative->nClusters[iSector][iRow]; iCl++) { + int32_t i = clNative->clusterOffset[iSector][iRow] + iCl; for (int32_t j = 0; j < GetMCLabelNID(i); j++) { uint32_t trackId = GetMCTrackObj(mTrackMCLabelsReverse, GetMCLabel(i, j)); if (trackId < lowestPadRow.size() && lowestPadRow[trackId] > iRow) { @@ -1113,12 +1115,21 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx } for (uint32_t i = 0; i < mTracking->mIOPtrs.nMergedTracks; i++) { const auto& trk = mTracking->mIOPtrs.mergedTracks[i]; - if (trk.OK() && lowestPadRow[i] != 255 && trk.NClustersFitted() > 70 && CAMath::Abs(trk.GetParam().GetQPt()) < 0.5) { - int32_t lowestRow = CAMath::Min(mTracking->mIOPtrs.mergedTrackHits[trk.FirstClusterRef()].row, mTracking->mIOPtrs.mergedTrackHits[trk.FirstClusterRef() + trk.NClusters() - 1].row); + if (trk.OK() && lowestPadRow[i] != 255 && trk.NClustersFitted() >= PADROW_CHECK_MINCLS && CAMath::Abs(trk.GetParam().GetQPt()) < 1.0) { + const auto& lowestCl = mTracking->mIOPtrs.mergedTrackHits[trk.FirstClusterRef()].row < mTracking->mIOPtrs.mergedTrackHits[trk.FirstClusterRef() + trk.NClusters() - 1].row ? mTracking->mIOPtrs.mergedTrackHits[trk.FirstClusterRef()] : mTracking->mIOPtrs.mergedTrackHits[trk.FirstClusterRef() + trk.NClusters() - 1]; + const int32_t lowestRow = lowestCl.row; mPadRow[0]->Fill(lowestPadRow[i], lowestRow, 1.f); mPadRow[1]->Fill(CAMath::ATan2(trk.GetParam().GetY(), trk.GetParam().GetX()), lowestRow, 1.f); - if (lowestPadRow[i] == 0 && lowestRow != 0) { - mPadRow[2]->Fill(CAMath::ATan2(trk.GetParam().GetY(), trk.GetParam().GetX()), lowestRow, 1.f); + if (lowestPadRow[i] < 10 && lowestRow > lowestPadRow[i] + 3) { + const auto& cl = clNative->clustersLinear[lowestCl.num]; + float x, y, z; + mTracking->GetTPCTransformHelper()->Transform(lowestCl.sector, lowestCl.row, cl.getPad(), cl.getTime(), x, y, z, trk.GetParam().GetTOffset()); + float phi = CAMath::ATan2(y, x); + mPadRow[2]->Fill(phi, lowestRow, 1.f); + if (CAMath::Abs(phi) < 0.15) { + const float time = cl.getTime(); + mPadRow[3]->Fill(mTracking->GetParam().GetUnscaledMult(time), lowestRow, 1.f); + } } } } @@ -1485,7 +1496,7 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx } } - if (mQATasks & taskClusterAttach) { + if ((mQATasks & taskClusterAttach) && !tracksExternal) { // Fill cluster histograms for (uint32_t iTrk = 0; iTrk < nReconstructedTracks; iTrk++) { const GPUTPCGMMergedTrack& track = mTracking->mIOPtrs.mergedTracks[iTrk]; @@ -1715,7 +1726,7 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx GPUWarning("No MC information available, only running partial TPC QA!"); } // mcAvail - if (mQATasks & taskTrackStatistics) { + if ((mQATasks & taskTrackStatistics) && !tracksExternal) { // Fill track statistic histograms std::vector> clusterAttachCounts; if (mcAvail) { @@ -1815,8 +1826,8 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx if (mQATasks & taskClusterCounts) { for (uint32_t iSector = 0; iSector < GPUCA_NSECTORS; iSector++) { for (uint32_t iRow = 0; iRow < GPUCA_ROW_COUNT; iRow++) { - for (uint32_t iCl = 0; iCl < mTracking->mIOPtrs.clustersNative->nClusters[iSector][iRow]; iCl++) { - uint32_t i = mTracking->mIOPtrs.clustersNative->clusterOffset[iSector][iRow] + iCl; + for (uint32_t iCl = 0; iCl < clNative->nClusters[iSector][iRow]; iCl++) { + uint32_t i = clNative->clusterOffset[iSector][iRow] + iCl; int32_t attach = mTracking->mIOPtrs.mergedTrackHitAttachment[i]; const auto& r = checkClusterState(attach, &mClusterCounts); @@ -1873,8 +1884,8 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx if (r.unattached) { mClusterCounts.nUnattached++; } - if (mTracking && mTracking->mIOPtrs.clustersNative) { - const auto& cl = mTracking->mIOPtrs.clustersNative->clustersLinear[i]; + if (mTracking && clNative) { + const auto& cl = clNative->clustersLinear[i]; mClRej[0]->Fill(cl.getPad() - GPUTPCGeometry::NPads(iRow) / 2 + 0.5, iRow, 1.f); if (!r.unattached && !r.protect) { mClRej[1]->Fill(cl.getPad() - GPUTPCGeometry::NPads(iRow) / 2 + 0.5, iRow, 1.f); @@ -1895,7 +1906,7 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx GPUInfo("QA Time: Cluster Counts:\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); } - if (mConfig.dumpToROOT) { + if (mConfig.dumpToROOT && !tracksExternal) { if (!clNative || !mTracking || !mTracking->mIOPtrs.mergedTrackHitAttachment || !mTracking->mIOPtrs.mergedTracks) { throw std::runtime_error("Cannot dump non o2::tpc::clusterNative clusters, need also hit attachmend and GPU tracks"); } @@ -2273,7 +2284,7 @@ int32_t GPUQA::DrawQAHistograms(TObjArray* qcout) mPClRejP = createGarbageCollected("p0", "", 0.0, 0.0, 1.0, 1.0); mPClRejP->Draw(); - for (int32_t i = 0; i < 3; i++) { + for (int32_t i = 0; i < 4; i++) { snprintf(name, 2048, "cpadrow%d", i); mCPadRow[i] = createGarbageCollected(name, name, 0, 0, 700, 700. * 2. / 3.); mCPadRow[i]->cd(); @@ -2842,19 +2853,28 @@ int32_t GPUQA::DrawQAHistograms(TObjArray* qcout) } } - for (int32_t i = 0; i < 3; i++) { + for (int32_t i = 0; i < 4; i++) { auto* e = mPadRow[i]; if (tout && !mConfig.inputHistogramsOnly) { e->Write(); } mPPadRow[i]->cd(); e->SetOption("colz"); - e->SetTitle(i == 2 ? "First Track Pad Row (row_{MC} = 0, row_{trk} > 0)" : "First Track Pad Row"); - e->GetXaxis()->SetTitle(i ? "#Phi (sector)" : "First MC Pad Row"); + std::string title = "First Track Pad Row (p_{T} > 1GeV, N_{Cl} #geq " + std::to_string(PADROW_CHECK_MINCLS); + if (i >= 2) { + title += ", row_{trk} > row_{MC} + 3, row_{MC} < 10"; + } + if (i >= 3) { + title += ", #Phi_{Cl} < 0.15"; + } + title += ")"; + + e->SetTitle(title.c_str()); + e->GetXaxis()->SetTitle(i == 3 ? "Local Occupancy" : (i ? "#Phi_{Cl} (sector)" : "First MC Pad Row")); e->GetYaxis()->SetTitle("First Pad Row"); e->Draw(); mCPadRow[i]->cd(); - static const constexpr char* PADROW_NAMES[3] = {"MC", "Phi", "Phi1"}; + static const constexpr char* PADROW_NAMES[4] = {"MC", "Phi", "Phi1", "Occ"}; mCPadRow[i]->Print(Form("%s/padRow%s.pdf", mConfig.plotsDir.c_str(), PADROW_NAMES[i])); if (mConfig.writeFileExt != "") { mCPadRow[i]->Print(Form("%s/padRow%s.%s", mConfig.plotsDir.c_str(), PADROW_NAMES[i], mConfig.writeFileExt.c_str())); diff --git a/GPU/GPUTracking/qa/GPUQA.h b/GPU/GPUTracking/qa/GPUQA.h index 54d1ceed9d365..7303ed62a9562 100644 --- a/GPU/GPUTracking/qa/GPUQA.h +++ b/GPU/GPUTracking/qa/GPUQA.h @@ -323,9 +323,9 @@ class GPUQA TPad* mPClRej[3]; TPad* mPClRejP; - TH2F* mPadRow[3]; - TCanvas* mCPadRow[3]; - TPad* mPPadRow[3]; + TH2F* mPadRow[4]; + TCanvas* mCPadRow[4]; + TPad* mPPadRow[4]; std::vector mHistClusterCount; From 215ac60fe27a46657b82fa2434923c28797c8d3d Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 4 Dec 2025 12:55:58 +0100 Subject: [PATCH 003/234] GPU QA Standalone: By default write histograms to output root file in plots folder --- GPU/GPUTracking/Standalone/Benchmark/standalone.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx b/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx index ca26f26d32612..857803d913372 100644 --- a/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx +++ b/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx @@ -197,6 +197,9 @@ int32_t ReadConfiguration(int argc, char** argv) printf("Can only produce QA pdf output when input files are specified!\n"); return 1; } + if (configStandalone.QA.enableLocalOutput && !configStandalone.QA.inputHistogramsOnly && configStandalone.QA.output == "" && configStandalone.QA.plotsDir != "") { + configStandalone.QA.output = configStandalone.QA.plotsDir + "/output.root"; + } if (configStandalone.QA.inputHistogramsOnly) { configStandalone.rundEdx = false; configStandalone.noEvents = true; From 4b0f130b0f0b5387247a075075add83a4cb09a32 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 3 Dec 2025 21:13:34 +0100 Subject: [PATCH 004/234] GPU: Remove non-working MI100 serialization workaround and obsolete StuckProtection --- GPU/GPUTracking/Base/GPUReconstructionCPU.h | 2 -- .../Base/opencl/GPUReconstructionOCL.cxx | 21 ------------------- .../Base/opencl/GPUReconstructionOCL.h | 1 - GPU/GPUTracking/Definitions/GPUSettingsList.h | 2 -- GPU/GPUTracking/Global/GPUChain.h | 2 -- .../Global/GPUChainTrackingSectorTracker.cxx | 3 --- prodtests/full-system-test/dpl-workflow.sh | 2 -- 7 files changed, 33 deletions(-) diff --git a/GPU/GPUTracking/Base/GPUReconstructionCPU.h b/GPU/GPUTracking/Base/GPUReconstructionCPU.h index a78a482db4e7a..d621d45fcd92b 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionCPU.h +++ b/GPU/GPUTracking/Base/GPUReconstructionCPU.h @@ -88,8 +88,6 @@ class GPUReconstructionCPU : public GPUReconstructionProcessing::KernelInterface int32_t ExitDevice() override; int32_t GetThread(); - virtual int32_t DoStuckProtection(int32_t stream, deviceEvent event) { return 0; } - // Pointers to tracker classes GPUProcessorProcessors mProcShadow; // Host copy of tracker objects that will be used on the GPU GPUConstantMem*& mProcessorsShadow = mProcShadow.mProcessorsProc; diff --git a/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL.cxx b/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL.cxx index 271fe494860cd..6954cfb3d6211 100644 --- a/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL.cxx +++ b/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL.cxx @@ -470,27 +470,6 @@ void GPUReconstructionOCL::ReleaseEvent(deviceEvent ev) { GPUChkErr(clReleaseEve void GPUReconstructionOCL::RecordMarker(deviceEvent* ev, int32_t stream) { GPUChkErr(clEnqueueMarkerWithWaitList(mInternals->command_queue[stream], 0, nullptr, ev->getEventList())); } -int32_t GPUReconstructionOCL::DoStuckProtection(int32_t stream, deviceEvent event) -{ - if (GetProcessingSettings().stuckProtection) { - cl_int tmp = 0; - for (int32_t i = 0; i <= GetProcessingSettings().stuckProtection / 50; i++) { - usleep(50); - clGetEventInfo(event.get(), CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(tmp), &tmp, nullptr); - if (tmp == CL_COMPLETE) { - break; - } - } - if (tmp != CL_COMPLETE) { - mGPUStuck = 1; - GPUErrorReturn("GPU Stuck, future processing in this component is disabled, skipping event (GPU Event State %d)", (int32_t)tmp); - } - } else { - clFinish(mInternals->command_queue[stream]); - } - return 0; -} - void GPUReconstructionOCL::SynchronizeGPU() { for (int32_t i = 0; i < mNStreams; i++) { diff --git a/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL.h b/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL.h index 958d5186bf41a..a52db1f2a737a 100644 --- a/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL.h +++ b/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL.h @@ -43,7 +43,6 @@ class GPUReconstructionOCL : public GPUReconstructionProcessing::KernelInterface virtual int32_t GPUChkErrInternal(const int64_t error, const char* file, int32_t line) const override; void SynchronizeGPU() override; - int32_t DoStuckProtection(int32_t stream, deviceEvent event) override; int32_t GPUDebug(const char* state = "UNKNOWN", int32_t stream = -1, bool force = false) override; void SynchronizeStream(int32_t stream) override; void SynchronizeEvents(deviceEvent* evList, int32_t nEvents = 1) override; diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index 5a075bf7f9a02..d70fac115eab7 100644 --- a/GPU/GPUTracking/Definitions/GPUSettingsList.h +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -301,7 +301,6 @@ BeginSubConfig(GPUSettingsProcessing, proc, configStandalone, "PROC", 0, "Proces AddOption(deviceNum, int32_t, -1, "gpuDevice", 0, "Set GPU device to use (-1: automatic, -2: for round-robin usage in timeslice-pipeline)") AddOption(gpuDeviceOnly, bool, false, "", 0, "Use only GPU as device (i.e. no CPU for OpenCL)") AddOption(globalInitMutex, bool, false, "", 0, "Use global mutex to synchronize initialization of multiple GPU instances") -AddOption(stuckProtection, int32_t, 0, "", 0, "Timeout in us, When AMD GPU is stuck, just continue processing and skip tracking, do not crash or stall the chain") AddOption(trdNCandidates, int32_t, 3, "", 0, "Number of branching track candidates for single input track during propagation") AddOption(trdTrackModelO2, bool, false, "", 0, "Use O2 track model instead of GPU track model for TRD tracking") AddOption(debugLevel, int32_t, -1, "debug", 'd', "Set debug level (-2 = silent, -1 = autoselect (-2 for O2, 0 for standalone))") @@ -383,7 +382,6 @@ AddOption(debugOnFailureMaxN, uint32_t, 1, "", 0, "Max number of times to run th AddOption(debugOnFailureMaxFiles, uint32_t, 0, "", 0, "Max number of files to have in the target folder") AddOption(debugOnFailureMaxSize, uint32_t, 0, "", 0, "Max size of existing dumps in the target folder in GB") AddOption(debugOnFailureDirectory, std::string, ".", "", 0, "Target folder for debug / dump") -AddOption(amdMI100SerializationWorkaround, bool, false, "", 0, "Enable workaround that mitigates MI100 serialization bug") AddOption(memoryStat, bool, false, "", 0, "Print memory statistics") AddVariable(eventDisplay, o2::gpu::GPUDisplayFrontendInterface*, nullptr) AddSubConfig(GPUSettingsProcessingRTC, rtc) diff --git a/GPU/GPUTracking/Global/GPUChain.h b/GPU/GPUTracking/Global/GPUChain.h index 9ce3da1092e83..6831fbd15080a 100644 --- a/GPU/GPUTracking/Global/GPUChain.h +++ b/GPU/GPUTracking/Global/GPUChain.h @@ -224,8 +224,6 @@ class GPUChain inline GPUChain* GetNextChainInQueue() { return mRec->GetNextChainInQueue(); } - virtual int32_t DoStuckProtection(int32_t stream, deviceEvent event) { return 0; } - template bool DoDebugAndDump(RecoStep step, uint32_t mask, T& processor, S T::*func, Args&&... args) { diff --git a/GPU/GPUTracking/Global/GPUChainTrackingSectorTracker.cxx b/GPU/GPUTracking/Global/GPUChainTrackingSectorTracker.cxx index 122eb709b4356..e2d68f10819fb 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingSectorTracker.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingSectorTracker.cxx @@ -149,9 +149,6 @@ int32_t GPUChainTracking::RunTPCTrackingSectors_internal() GPUTPCTracker& trk = processors()->tpcTrackers[iSector]; GPUTPCTracker& trkShadow = doGPU ? processorsShadow()->tpcTrackers[iSector] : trk; int32_t useStream = StreamForSector(iSector); - if (GetProcessingSettings().amdMI100SerializationWorkaround) { - SynchronizeStream(useStream); // TODO: Remove this workaround once fixed on MI100 - } if (GetProcessingSettings().debugLevel >= 3) { GPUInfo("Creating Sector Data (Sector %d)", iSector); diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index ce5607d361cbe..754349c87eecc 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -284,8 +284,6 @@ if [[ $GPUTYPE == "HIP" ]]; then if [[ ${EPN_NODE_MI100:-} == "1" && ${DISABLE_MI100_SERIALIZATION:-0} != 1 ]]; then if [[ -n ${OPTIMIZED_PARALLEL_ASYNC:-} ]] || [[ $EPNSYNCMODE == 1 && ${FULL_MI100_SERIALIZATION:-0} == 1 ]]; then GPU_CONFIG_KEY+="GPU_proc.serializeGPU=3;" - elif [[ $EPNSYNCMODE == 1 ]]; then - GPU_CONFIG_KEY+="GPU_proc.amdMI100SerializationWorkaround=1;" fi fi #export HSA_TOOLS_LIB=/opt/rocm/lib/librocm-debug-agent.so.2 From 534219337bb9ccaebaca12b902bdac2a3fb513a2 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 8 Dec 2025 09:32:03 +0100 Subject: [PATCH 005/234] GPU QA: Dump also text output to output folder --- GPU/GPUTracking/qa/GPUQA.cxx | 11 ++++++++++- GPU/GPUTracking/qa/GPUQA.h | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/GPU/GPUTracking/qa/GPUQA.cxx b/GPU/GPUTracking/qa/GPUQA.cxx index 28b603f77e2ff..3c176031dec08 100644 --- a/GPU/GPUTracking/qa/GPUQA.cxx +++ b/GPU/GPUTracking/qa/GPUQA.cxx @@ -3141,7 +3141,9 @@ void GPUQA::PrintClusterCount(int32_t mode, int32_t& num, const char* name, uint createHist(mHistClusterCount[num], name2, name, 1000, 0, mConfig.histMaxNClusters, 1000, 0, 100); } else if (mode == 0) { if (normalization && mConfig.enableLocalOutput) { - printf("\t%40s: %'12" PRIu64 " (%6.2f%%)\n", name, n, 100.f * n / normalization); + for (uint32_t i = 0; i < 1 + (mTextDump != nullptr); i++) { + fprintf(i ? mTextDump : stdout, "\t%40s: %'12" PRIu64 " (%6.2f%%)\n", name, n, 100.f * n / normalization); + } } if (mConfig.clusterRejectionHistograms) { float ratio = 100.f * n / std::max(normalization, 1); @@ -3153,6 +3155,9 @@ void GPUQA::PrintClusterCount(int32_t mode, int32_t& num, const char* name, uint int32_t GPUQA::DoClusterCounts(uint64_t* attachClusterCounts, int32_t mode) { + if (mConfig.enableLocalOutput && !mConfig.inputHistogramsOnly && mConfig.plotsDir != "") { + mTextDump = fopen((mConfig.plotsDir + "/clusterCounts.txt").c_str(), "w+"); + } int32_t num = 0; if (mcPresent() && (mQATasks & taskClusterAttach) && attachClusterCounts) { for (int32_t i = 0; i < N_CLS_HIST; i++) { // TODO: Check that these counts are still printed correctly! @@ -3191,6 +3196,10 @@ int32_t GPUQA::DoClusterCounts(uint64_t* attachClusterCounts, int32_t mode) PrintClusterCount(mode, num, "Correctly Attached all-trk normalized", mClusterCounts.nCorrectlyAttachedNormalized, mClusterCounts.nTotal); PrintClusterCount(mode, num, "Correctly Attached non-fake normalized", mClusterCounts.nCorrectlyAttachedNormalizedNonFake, mClusterCounts.nTotal); } + if (mTextDump) { + fclose(mTextDump); + mTextDump = nullptr; + } return num; } diff --git a/GPU/GPUTracking/qa/GPUQA.h b/GPU/GPUTracking/qa/GPUQA.h index 7303ed62a9562..b42fa804c6212 100644 --- a/GPU/GPUTracking/qa/GPUQA.h +++ b/GPU/GPUTracking/qa/GPUQA.h @@ -62,6 +62,7 @@ class GPUQA #else #include "GPUTPCDef.h" +#include #include #include #include @@ -365,6 +366,7 @@ class GPUQA int32_t mMCTrackMin = -1, mMCTrackMax = -1; const o2::tpc::ClusterNativeAccess* mClNative = nullptr; + FILE* mTextDump = nullptr; }; inline bool GPUQA::SuppressTrack(int32_t iTrack) const { return (mConfig.matchMCLabels.size() && !mGoodTracks[mNEvents][iTrack]); } From 7eb731a2da99bc377efdb2b5cd0c33a54fa49137 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 10 Dec 2025 19:16:24 +0100 Subject: [PATCH 006/234] GPU QA: Fix some task number inconsistencies --- GPU/GPUTracking/Global/GPUChainTracking.cxx | 4 +- GPU/GPUTracking/qa/GPUQA.cxx | 223 ++++++++++---------- GPU/GPUTracking/qa/GPUQA.h | 16 +- GPU/Workflow/src/GPUWorkflowSpec.cxx | 2 +- 4 files changed, 131 insertions(+), 114 deletions(-) diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index 14d0e04eb4dd3..0e7d4bc4f436e 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -475,7 +475,7 @@ int32_t GPUChainTracking::ForceInitQA() qa.reset(new GPUQA(this)); } if (!GetQA()->IsInitialized()) { - return GetQA()->InitQA(); + return GetQA()->InitQA(GetProcessingSettings().runQA <= 0 ? -GetProcessingSettings().runQA : GPUQA::tasksAutomatic); } return 0; } @@ -690,7 +690,7 @@ int32_t GPUChainTracking::RunChain() } const bool needQA = GPUQA::QAAvailable() && (GetProcessingSettings().runQA || (GetProcessingSettings().eventDisplay && (mIOPtrs.nMCInfosTPC || GetProcessingSettings().runMC))); if (needQA && GetQA()->IsInitialized() == false) { - if (GetQA()->InitQA(GetProcessingSettings().runQA ? -GetProcessingSettings().runQA : -1)) { + if (GetQA()->InitQA(GetProcessingSettings().runQA <= 0 ? -GetProcessingSettings().runQA : GPUQA::tasksAutomatic)) { return 1; } } diff --git a/GPU/GPUTracking/qa/GPUQA.cxx b/GPU/GPUTracking/qa/GPUQA.cxx index 3c176031dec08..852ac5c1feefb 100644 --- a/GPU/GPUTracking/qa/GPUQA.cxx +++ b/GPU/GPUTracking/qa/GPUQA.cxx @@ -544,7 +544,8 @@ int32_t GPUQA::InitQACreateHistograms() createHist(mT0[0], "tracks_t0", "tracks_t0", (maxTime + 1) / 10, 0, maxTime); createHist(mT0[1], "tracks_t0_res", "tracks_t0_res", 1000, -100, 100); createHist(mClXY, "clXY", "clXY", 1000, -250, 250, 1000, -250, 250); // TODO: Pass name only once - + } + if (mQATasks & taskClusterRejection) { const int padCount = GPUTPCGeometry::NPads(GPUCA_ROW_COUNT - 1); for (int32_t i = 0; i < 3; i++) { snprintf(name, 2048, "clrej_%d", i); @@ -577,8 +578,8 @@ int32_t GPUQA::InitQACreateHistograms() int32_t GPUQA::loadHistograms(std::vector& i1, std::vector& i2, std::vector& i3, std::vector& i4, int32_t tasks) { - if (tasks == -1) { - tasks = taskDefaultPostprocess; + if (tasks == tasksAutomatic) { + tasks = tasksDefaultPostprocess; } if (mQAInitialized && (!mHaveExternalHists || tasks != mQATasks)) { throw std::runtime_error("QA not initialized or initialized with different task array"); @@ -593,7 +594,7 @@ int32_t GPUQA::loadHistograms(std::vector& i1, std::vector& i2, std: mHistGraph_pos.clear(); mHaveExternalHists = true; if (mConfig.noMC) { - tasks &= tasksNoQC; + tasks &= tasksAllNoQC; } mQATasks = tasks; if (InitQACreateHistograms()) { @@ -806,8 +807,8 @@ int32_t GPUQA::InitQA(int32_t tasks) if (mQAInitialized) { throw std::runtime_error("QA already initialized"); } - if (tasks == -1) { - tasks = taskDefault; + if (tasks == tasksAutomatic) { + tasks = tasksDefault; } mHist1D = new std::vector; @@ -815,7 +816,7 @@ int32_t GPUQA::InitQA(int32_t tasks) mHist1Dd = new std::vector; mHistGraph = new std::vector; if (mConfig.noMC) { - tasks &= tasksNoQC; + tasks &= tasksAllNoQC; } mQATasks = tasks; @@ -1823,7 +1824,7 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx uint32_t nCl = clNative ? clNative->nClustersTotal : mTracking->GetProcessors()->tpcMerger.NMaxClusters(); mClusterCounts.nTotal += nCl; - if (mQATasks & taskClusterCounts) { + if (mQATasks & (taskClusterCounts | taskClusterRejection)) { for (uint32_t iSector = 0; iSector < GPUCA_NSECTORS; iSector++) { for (uint32_t iRow = 0; iRow < GPUCA_ROW_COUNT; iRow++) { for (uint32_t iCl = 0; iCl < clNative->nClusters[iSector][iRow]; iCl++) { @@ -1831,64 +1832,68 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx int32_t attach = mTracking->mIOPtrs.mergedTrackHitAttachment[i]; const auto& r = checkClusterState(attach, &mClusterCounts); - if (mcAvail) { - float totalWeight = 0, weight400 = 0, weight40 = 0; - for (int32_t j = 0; j < GetMCLabelNID(i); j++) { - const auto& label = GetMCLabel(i, j); - if (GetMCLabelID(label) >= 0) { - totalWeight += GetMCLabelWeight(label); - if (GetMCTrackObj(mMCParam, label).pt >= 0.4) { - weight400 += GetMCLabelWeight(label); - } - if (GetMCTrackObj(mMCParam, label).pt <= 0.04) { - weight40 += GetMCLabelWeight(label); + if (mQATasks & taskClusterRejection) { + if (mcAvail) { + float totalWeight = 0, weight400 = 0, weight40 = 0; + for (int32_t j = 0; j < GetMCLabelNID(i); j++) { + const auto& label = GetMCLabel(i, j); + if (GetMCLabelID(label) >= 0) { + totalWeight += GetMCLabelWeight(label); + if (GetMCTrackObj(mMCParam, label).pt >= 0.4) { + weight400 += GetMCLabelWeight(label); + } + if (GetMCTrackObj(mMCParam, label).pt <= 0.04) { + weight40 += GetMCLabelWeight(label); + } } } - } - if (totalWeight > 0 && 10.f * weight400 >= totalWeight) { - if (!r.unattached && !r.protect && !r.physics) { - mClusterCounts.nFakeRemove400++; - int32_t totalFake = weight400 < 0.9f * totalWeight; - if (totalFake) { - mClusterCounts.nFullFakeRemove400++; - } - /*printf("Fake removal (%d): Hit %7d, attached %d lowPt %d looper %d tube200 %d highIncl %d tube %d bad %d recPt %7.2f recLabel %6d", totalFake, i, (int32_t) (mClusterParam[i].attached || mClusterParam[i].fakeAttached), - (int32_t) lowPt, (int32_t) ((attach & gputpcgmmergertypes::attachGoodLeg) == 0), (int32_t) ((attach & gputpcgmmergertypes::attachTube) && mev200), - (int32_t) ((attach & gputpcgmmergertypes::attachHighIncl) != 0), (int32_t) ((attach & gputpcgmmergertypes::attachTube) != 0), (int32_t) ((attach & gputpcgmmergertypes::attachGood) == 0), - fabsf(qpt) > 0 ? 1.f / qpt : 0.f, id); - for (int32_t j = 0;j < GetMCLabelNID(i);j++) - { - //if (GetMCLabelID(i, j) < 0) break; - printf(" - label%d %6d weight %5d", j, GetMCLabelID(i, j), (int32_t) GetMCLabelWeight(i, j)); - if (GetMCLabelID(i, j) >= 0) printf(" - pt %7.2f", mMCParam[GetMCLabelID(i, j)].pt); - else printf(" "); + if (totalWeight > 0 && 10.f * weight400 >= totalWeight) { + if (!r.unattached && !r.protect && !r.physics) { + mClusterCounts.nFakeRemove400++; + int32_t totalFake = weight400 < 0.9f * totalWeight; + if (totalFake) { + mClusterCounts.nFullFakeRemove400++; + } + /*printf("Fake removal (%d): Hit %7d, attached %d lowPt %d looper %d tube200 %d highIncl %d tube %d bad %d recPt %7.2f recLabel %6d", totalFake, i, (int32_t) (mClusterParam[i].attached || mClusterParam[i].fakeAttached), + (int32_t) lowPt, (int32_t) ((attach & gputpcgmmergertypes::attachGoodLeg) == 0), (int32_t) ((attach & gputpcgmmergertypes::attachTube) && mev200), + (int32_t) ((attach & gputpcgmmergertypes::attachHighIncl) != 0), (int32_t) ((attach & gputpcgmmergertypes::attachTube) != 0), (int32_t) ((attach & gputpcgmmergertypes::attachGood) == 0), + fabsf(qpt) > 0 ? 1.f / qpt : 0.f, id); + for (int32_t j = 0;j < GetMCLabelNID(i);j++) + { + //if (GetMCLabelID(i, j) < 0) break; + printf(" - label%d %6d weight %5d", j, GetMCLabelID(i, j), (int32_t) GetMCLabelWeight(i, j)); + if (GetMCLabelID(i, j) >= 0) printf(" - pt %7.2f", mMCParam[GetMCLabelID(i, j)].pt); + else printf(" "); + } + printf("\n");*/ } - printf("\n");*/ + mClusterCounts.nAbove400++; } - mClusterCounts.nAbove400++; - } - if (totalWeight > 0 && weight40 >= 0.9 * totalWeight) { - mClusterCounts.nBelow40++; - if (r.protect || r.physics) { - mClusterCounts.nFakeProtect40++; + if (totalWeight > 0 && weight40 >= 0.9 * totalWeight) { + mClusterCounts.nBelow40++; + if (r.protect || r.physics) { + mClusterCounts.nFakeProtect40++; + } } } - } - if (r.physics) { - mClusterCounts.nPhysics++; - } - if (r.protect) { - mClusterCounts.nProt++; - } - if (r.unattached) { - mClusterCounts.nUnattached++; + if (r.physics) { + mClusterCounts.nPhysics++; + } + if (r.protect) { + mClusterCounts.nProt++; + } + if (r.unattached) { + mClusterCounts.nUnattached++; + } } - if (mTracking && clNative) { - const auto& cl = clNative->clustersLinear[i]; - mClRej[0]->Fill(cl.getPad() - GPUTPCGeometry::NPads(iRow) / 2 + 0.5, iRow, 1.f); - if (!r.unattached && !r.protect) { - mClRej[1]->Fill(cl.getPad() - GPUTPCGeometry::NPads(iRow) / 2 + 0.5, iRow, 1.f); + if (mQATasks & taskClusterRejection) { + if (mTracking && clNative) { + const auto& cl = clNative->clustersLinear[i]; + mClRej[0]->Fill(cl.getPad() - GPUTPCGeometry::NPads(iRow) / 2 + 0.5, iRow, 1.f); + if (!r.unattached && !r.protect) { + mClRej[1]->Fill(cl.getPad() - GPUTPCGeometry::NPads(iRow) / 2 + 0.5, iRow, 1.f); + } } } } @@ -2271,7 +2276,9 @@ int32_t GPUQA::DrawQAHistograms(TObjArray* qcout) mCClXY->cd(); mPClXY = createGarbageCollected("p0", "", 0.0, 0.0, 1.0, 1.0); mPClXY->Draw(); + } + if (mQATasks & taskClusterRejection) { for (int32_t i = 0; i < 3; i++) { snprintf(name, 2048, "cnclrej%d", i); mCClRej[i] = createGarbageCollected(name, name, 0, 0, 700, 700. * 2. / 3.); @@ -2283,7 +2290,9 @@ int32_t GPUQA::DrawQAHistograms(TObjArray* qcout) mCClRejP->cd(); mPClRejP = createGarbageCollected("p0", "", 0.0, 0.0, 1.0, 1.0); mPClRejP->Draw(); + } + if (mQATasks & taskClusterAttach) { for (int32_t i = 0; i < 4; i++) { snprintf(name, 2048, "cpadrow%d", i); mCPadRow[i] = createGarbageCollected(name, name, 0, 0, 700, 700. * 2. / 3.); @@ -3034,7 +3043,7 @@ int32_t GPUQA::DrawQAHistograms(TObjArray* qcout) } } - mPClXY->cd(); + mPClXY->cd(); // TODO: This should become a separate task category mClXY->SetOption("colz"); mClXY->Draw(); mCClXY->cd(); @@ -3042,61 +3051,61 @@ int32_t GPUQA::DrawQAHistograms(TObjArray* qcout) if (mConfig.writeFileExt != "") { mCClXY->Print(Form("%s/clustersXY.%s", mConfig.plotsDir.c_str(), mConfig.writeFileExt.c_str())); } + } - if (mQATasks & taskClusterCounts) { - mClRej[2]->Divide(mClRej[1], mClRej[0]); + if (mQATasks & taskClusterRejection) { + mClRej[2]->Divide(mClRej[1], mClRej[0]); - for (int32_t i = 0; i < 3; i++) { - if (tout && !mConfig.inputHistogramsOnly) { - mClRej[i]->Write(); - } - mPClRej[i]->cd(); - mClRej[i]->SetTitle(REJECTED_NAMES[i]); - mClRej[i]->SetOption("colz"); - mClRej[i]->Draw(); - mCClRej[i]->cd(); - mCClRej[i]->Print(Form("%s/clustersRej%d%s.pdf", mConfig.plotsDir.c_str(), i, REJECTED_NAMES[i])); - if (mConfig.writeFileExt != "") { - mCClRej[i]->Print(Form("%s/clustersRej%d%s.%s", mConfig.plotsDir.c_str(), i, REJECTED_NAMES[i], mConfig.writeFileExt.c_str())); - } + for (int32_t i = 0; i < 3; i++) { + if (tout && !mConfig.inputHistogramsOnly) { + mClRej[i]->Write(); + } + mPClRej[i]->cd(); + mClRej[i]->SetTitle(REJECTED_NAMES[i]); + mClRej[i]->SetOption("colz"); + mClRej[i]->Draw(); + mCClRej[i]->cd(); + mCClRej[i]->Print(Form("%s/clustersRej%d%s.pdf", mConfig.plotsDir.c_str(), i, REJECTED_NAMES[i])); + if (mConfig.writeFileExt != "") { + mCClRej[i]->Print(Form("%s/clustersRej%d%s.%s", mConfig.plotsDir.c_str(), i, REJECTED_NAMES[i], mConfig.writeFileExt.c_str())); } + } - mPClRejP->cd(); - for (int32_t k = 0; k < ConfigNumInputs; k++) { - auto* tmp = mClRej[0]; - if (GetHist(tmp, tin, k, nNewInput) == nullptr) { - continue; - } - TH1D* proj1 = tmp->ProjectionY(Form("clrejptmp1%d", k)); // TODO: Clean up names - proj1->SetDirectory(nullptr); - tmp = mClRej[1]; - if (GetHist(tmp, tin, k, nNewInput) == nullptr) { - continue; - } - TH1D* proj2 = tmp->ProjectionY(Form("clrejptmp2%d", k)); - proj2->SetDirectory(nullptr); + mPClRejP->cd(); + for (int32_t k = 0; k < ConfigNumInputs; k++) { + auto* tmp = mClRej[0]; + if (GetHist(tmp, tin, k, nNewInput) == nullptr) { + continue; + } + TH1D* proj1 = tmp->ProjectionY(Form("clrejptmp1%d", k)); // TODO: Clean up names + proj1->SetDirectory(nullptr); + tmp = mClRej[1]; + if (GetHist(tmp, tin, k, nNewInput) == nullptr) { + continue; + } + TH1D* proj2 = tmp->ProjectionY(Form("clrejptmp2%d", k)); + proj2->SetDirectory(nullptr); - auto* e = mClRejP; - if (GetHist(e, tin, k, nNewInput) == nullptr) { - continue; - } - e->Divide(proj2, proj1); - if (tout && !mConfig.inputHistogramsOnly && k == 0) { - e->Write(); - } - delete proj1; - delete proj2; - e->SetMinimum(-0.02); - e->SetMaximum(0.22); - e->SetTitle("Rejected Clusters"); - e->GetXaxis()->SetTitle("Pad Row"); - e->GetYaxis()->SetTitle("Rejected Clusters (fraction)"); - e->Draw(k == 0 ? "" : "same"); + auto* e = mClRejP; + if (GetHist(e, tin, k, nNewInput) == nullptr) { + continue; } - mPClRejP->Print(Form("%s/clustersRejProjected.pdf", mConfig.plotsDir.c_str())); - if (mConfig.writeFileExt != "") { - mPClRejP->Print(Form("%s/clustersRejProjected.%s", mConfig.plotsDir.c_str(), mConfig.writeFileExt.c_str())); + e->Divide(proj2, proj1); + if (tout && !mConfig.inputHistogramsOnly && k == 0) { + e->Write(); } + delete proj1; + delete proj2; + e->SetMinimum(-0.02); + e->SetMaximum(0.22); + e->SetTitle("Rejected Clusters"); + e->GetXaxis()->SetTitle("Pad Row"); + e->GetYaxis()->SetTitle("Rejected Clusters (fraction)"); + e->Draw(k == 0 ? "" : "same"); + } + mPClRejP->Print(Form("%s/clustersRejProjected.pdf", mConfig.plotsDir.c_str())); + if (mConfig.writeFileExt != "") { + mPClRejP->Print(Form("%s/clustersRejProjected.%s", mConfig.plotsDir.c_str(), mConfig.writeFileExt.c_str())); } } diff --git a/GPU/GPUTracking/qa/GPUQA.h b/GPU/GPUTracking/qa/GPUQA.h index b42fa804c6212..3dd49e2ec1373 100644 --- a/GPU/GPUTracking/qa/GPUQA.h +++ b/GPU/GPUTracking/qa/GPUQA.h @@ -56,6 +56,10 @@ class GPUQA static bool QAAvailable() { return false; } static bool IsInitialized() { return false; } void UpdateChain(GPUChainTracking* chain) {} + + enum QA_TASKS { + tasksAutomatic = 0 + }; }; } // namespace o2::gpu @@ -146,16 +150,20 @@ class GPUQA static constexpr int32_t MC_LABEL_INVALID = -1e9; - enum QA_TASKS { + enum QA_TASKS { // TODO: make this in32_t typed taskTrackingEff = 1, taskTrackingRes = 2, taskTrackingResPull = 4, + tasksAllMC = 8 - 1, taskClusterAttach = 8, taskTrackStatistics = 16, taskClusterCounts = 32, - taskDefault = 63, - taskDefaultPostprocess = 31, - tasksNoQC = 56 + taskClusterRejection = 64, + tasksAll = 128 - 1, + tasksDefault = tasksAll, + tasksDefaultPostprocess = tasksDefault & ~taskClusterCounts, + tasksAllNoQC = tasksAll & ~tasksAllMC, + tasksAutomatic = -1 }; private: diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index d7ea772c31653..fb1d489a8479d 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -180,7 +180,7 @@ void GPURecoWorkflowSpec::init(InitContext& ic) mConfig->configQA.shipToQC = true; if (!mConfig->configProcessing.runQA) { mConfig->configQA.enableLocalOutput = false; - mQATaskMask = (mSpecConfig.processMC ? 15 : 0) | (mConfig->configQA.clusterRejectionHistograms ? 32 : 0); + mQATaskMask = (mSpecConfig.processMC ? 15 : 0) | (mConfig->configQA.clusterRejectionHistograms ? 32 : 0); // TODO: Clean up using numeric flags! mConfig->configProcessing.runQA = -mQATaskMask; } } From 4d0047ce8f4c45fe0ed7abe664b230a163d39d78 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 29 Oct 2025 14:45:23 +0100 Subject: [PATCH 007/234] GPU TPC: Fix deterministic mode in combination of propagation of MC labels --- GPU/GPUTracking/Global/GPUChainTracking.h | 1 + .../Global/GPUChainTrackingClusterizer.cxx | 92 ++++++++++++++----- 2 files changed, 72 insertions(+), 21 deletions(-) diff --git a/GPU/GPUTracking/Global/GPUChainTracking.h b/GPU/GPUTracking/Global/GPUChainTracking.h index 8de49cc954e35..4b07aadfad357 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.h +++ b/GPU/GPUTracking/Global/GPUChainTracking.h @@ -306,6 +306,7 @@ class GPUChainTracking : public GPUChain void RunTPCClusterFilter(o2::tpc::ClusterNativeAccess* clusters, std::function allocator, bool applyClusterCuts); bool NeedTPCClustersOnGPU(); void WriteReducedClusters(); + void SortClusters(bool buildNativeGPU, bool propagateMCLabels, o2::tpc::ClusterNativeAccess* clusterAccess, o2::tpc::ClusterNative* clusters); template int32_t RunTRDTrackingInternal(); uint32_t StreamForSector(uint32_t sector) const; diff --git a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx index fdce8ef5a127d..c4566ffb968a7 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx @@ -57,6 +57,8 @@ #include "utils/VcShim.h" #include "utils/strtag.h" #include +#include +#include using namespace o2::gpu; using namespace o2::tpc; @@ -762,14 +764,13 @@ int32_t GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) ClusterNative* tmpNativeClusters = nullptr; std::unique_ptr tmpNativeClusterBuffer; - // setup MC Labels - bool propagateMCLabels = GetProcessingSettings().runMC && processors()->ioPtrs.tpcPackedDigits && processors()->ioPtrs.tpcPackedDigits->tpcDigitsMC; + const bool buildNativeGPU = doGPU && NeedTPCClustersOnGPU(); + const bool buildNativeHost = (mRec->GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCClusters) || GetProcessingSettings().deterministicGPUReconstruction; // TODO: Should do this also when clusters are needed for later steps on the host but not requested as output + const bool propagateMCLabels = buildNativeHost && GetProcessingSettings().runMC && processors()->ioPtrs.tpcPackedDigits && processors()->ioPtrs.tpcPackedDigits->tpcDigitsMC; + const bool sortClusters = buildNativeHost && (GetProcessingSettings().deterministicGPUReconstruction || GetProcessingSettings().debugLevel >= 4); auto* digitsMC = propagateMCLabels ? processors()->ioPtrs.tpcPackedDigits->tpcDigitsMC : nullptr; - bool buildNativeGPU = doGPU && NeedTPCClustersOnGPU(); - bool buildNativeHost = (mRec->GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCClusters) || GetProcessingSettings().deterministicGPUReconstruction; // TODO: Should do this also when clusters are needed for later steps on the host but not requested as output - mInputsHost->mNClusterNative = mInputsShadow->mNClusterNative = mRec->MemoryScalers()->nTPCHits * tpcHitLowOccupancyScalingFactor; if (buildNativeGPU) { AllocateRegisteredMemory(mInputsHost->mResourceClusterNativeBuffer); @@ -1281,21 +1282,20 @@ int32_t GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) } ClusterNativeAccess::ConstMCLabelContainerView* mcLabelsConstView = nullptr; - if (propagateMCLabels) { - // TODO: write to buffer directly + if (propagateMCLabels) { // TODO: write to buffer directly o2::dataformats::MCTruthContainer mcLabels; std::pair buffer; - if (!GetProcessingSettings().tpcWriteClustersAfterRejection && mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clusterLabels)] && mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clusterLabels)]->useExternal()) { - if (!mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clusterLabels)]->allocator) { + auto& labelOutputControl = mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clusterLabels)]; + if (!GetProcessingSettings().tpcWriteClustersAfterRejection && !sortClusters && labelOutputControl && labelOutputControl->useExternal()) { + if (!labelOutputControl->allocator) { throw std::runtime_error("Cluster MC Label buffer missing"); } - ClusterNativeAccess::ConstMCLabelContainerViewWithBuffer* container = reinterpret_cast(mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clusterLabels)]->allocator(0)); + ClusterNativeAccess::ConstMCLabelContainerViewWithBuffer* container = reinterpret_cast(labelOutputControl->allocator(0)); buffer = {&container->first, &container->second}; } else { mIOMem.clusterNativeMCView = std::make_unique(); mIOMem.clusterNativeMCBuffer = std::make_unique(); - buffer.first = mIOMem.clusterNativeMCBuffer.get(); - buffer.second = mIOMem.clusterNativeMCView.get(); + buffer = {mIOMem.clusterNativeMCBuffer.get(), mIOMem.clusterNativeMCView.get()}; } assert(propagateMCLabels ? mcLinearLabels.header.size() == nClsTotal : true); @@ -1350,15 +1350,8 @@ int32_t GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) if (doGPU && synchronizeCalibUpdate) { SynchronizeStream(0); } - if (buildNativeHost && (GetProcessingSettings().deterministicGPUReconstruction || GetProcessingSettings().debugLevel >= 4)) { - for (uint32_t i = 0; i < NSECTORS; i++) { - for (uint32_t j = 0; j < GPUCA_ROW_COUNT; j++) { - std::sort(&tmpNativeClusters[tmpNativeAccess->clusterOffset[i][j]], &tmpNativeClusters[tmpNativeAccess->clusterOffset[i][j] + tmpNativeAccess->nClusters[i][j]]); - } - } - if (buildNativeGPU) { - GPUMemCpy(RecoStep::TPCClusterFinding, (void*)mInputsShadow->mPclusterNativeBuffer, (const void*)tmpNativeClusters, nClsTotal * sizeof(tmpNativeClusters[0]), -1, true); - } + if (sortClusters) { + SortClusters(buildNativeGPU, propagateMCLabels, tmpNativeAccess, tmpNativeClusters); } mRec->MemoryScalers()->nTPCHits = nClsTotal; mRec->PopNonPersistentMemory(RecoStep::TPCClusterFinding, qStr2Tag("TPCCLUST")); @@ -1374,3 +1367,60 @@ int32_t GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) #endif return 0; } + +void GPUChainTracking::SortClusters(bool buildNativeGPU, bool propagateMCLabels, ClusterNativeAccess* clusterAccess, ClusterNative* clusters) +{ + if (propagateMCLabels) { + std::vector clsOrder(clusterAccess->nClustersTotal); + std::iota(clsOrder.begin(), clsOrder.end(), 0); + std::vector tmpClusters; + for (uint32_t i = 0; i < NSECTORS; i++) { + for (uint32_t j = 0; j < GPUCA_ROW_COUNT; j++) { + const uint32_t offset = clusterAccess->clusterOffset[i][j]; + std::sort(&clsOrder[offset], &clsOrder[offset + clusterAccess->nClusters[i][j]], [&clusters](const uint32_t a, const uint32_t b) { + return clusters[a] < clusters[b]; + }); + tmpClusters.resize(clusterAccess->nClusters[i][j]); + memcpy(tmpClusters.data(), &clusters[offset], clusterAccess->nClusters[i][j] * sizeof(tmpClusters[0])); + for (uint32_t k = 0; k < tmpClusters.size(); k++) { + clusters[offset + k] = tmpClusters[clsOrder[offset + k] - offset]; + } + } + } + tmpClusters.clear(); + + std::pair labelBuffer; + GPUOutputControl* labelOutput = mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clusterLabels)]; + std::unique_ptr tmpUniqueContainerView; + std::unique_ptr tmpUniqueContainerBuffer; + if (labelOutput && labelOutput->allocator) { + ClusterNativeAccess::ConstMCLabelContainerViewWithBuffer* labelContainer = reinterpret_cast(labelOutput->allocator(0)); + labelBuffer = {&labelContainer->first, &labelContainer->second}; + } else { + tmpUniqueContainerView = std::move(mIOMem.clusterNativeMCView); + tmpUniqueContainerBuffer = std::move(mIOMem.clusterNativeMCBuffer); + mIOMem.clusterNativeMCView = std::make_unique(); + mIOMem.clusterNativeMCBuffer = std::make_unique(); + labelBuffer = {mIOMem.clusterNativeMCBuffer.get(), mIOMem.clusterNativeMCView.get()}; + } + + o2::dataformats::MCLabelContainer tmpContainer; + for (uint32_t i = 0; i < clusterAccess->nClustersTotal; i++) { + for (const auto& element : clusterAccess->clustersMCTruth->getLabels(clsOrder[i])) { + tmpContainer.addElement(i, element); + } + } + tmpContainer.flatten_to(*labelBuffer.first); + *labelBuffer.second = *labelBuffer.first; + clusterAccess->clustersMCTruth = labelBuffer.second; + } else { + for (uint32_t i = 0; i < NSECTORS; i++) { + for (uint32_t j = 0; j < GPUCA_ROW_COUNT; j++) { + std::sort(&clusters[clusterAccess->clusterOffset[i][j]], &clusters[clusterAccess->clusterOffset[i][j] + clusterAccess->nClusters[i][j]]); + } + } + } + if (buildNativeGPU) { + GPUMemCpy(RecoStep::TPCClusterFinding, (void*)mInputsShadow->mPclusterNativeBuffer, (const void*)clusters, clusterAccess->nClustersTotal * sizeof(clusters[0]), -1, true); + } +} From 07e63da6ecc1733b0d6b5ce28afc7c852f1b0a89 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Fri, 12 Dec 2025 10:19:12 +0100 Subject: [PATCH 008/234] DPL: fix reversed index when filling DataProcessingStates --- Framework/Core/src/DataRelayer.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/Core/src/DataRelayer.cxx b/Framework/Core/src/DataRelayer.cxx index df95aeda92a2b..01e7a2b29fd35 100644 --- a/Framework/Core/src/DataRelayer.cxx +++ b/Framework/Core/src/DataRelayer.cxx @@ -1055,7 +1055,7 @@ void DataRelayer::sendContextState() char* buffer = relayerSlotState + written; for (size_t ci = 0; ci < mTimesliceIndex.size(); ++ci) { for (size_t si = 0; si < mDistinctRoutesIndex.size(); ++si) { - int index = si * mTimesliceIndex.size() + ci; + int index = ci * mDistinctRoutesIndex.size() + si; int value = static_cast(mCachedStateMetrics[index]); buffer[si] = value + '0'; // Anything which is done is actually already empty, From 16f1a93b6982837ef3f188a4b9067888d843e874 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Sat, 13 Dec 2025 09:17:14 +0100 Subject: [PATCH 009/234] Cleanup jobutils2 to work on ARM (#14901) --- Utilities/Tools/jobutils2.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Utilities/Tools/jobutils2.sh b/Utilities/Tools/jobutils2.sh index ba96b97da090b..b7c8466f54313 100644 --- a/Utilities/Tools/jobutils2.sh +++ b/Utilities/Tools/jobutils2.sh @@ -395,10 +395,13 @@ getNumberOfPhysicalCPUCores() { fi else # Do something under GNU/Linux platform - CORESPERSOCKET=`lscpu | grep "Core(s) per socket" | awk '{print $4}'` - SOCKETS=`lscpu | grep "Socket(s)" | awk '{print $2}'` + # + # Gets the cores per socket by counting unique cores on socket 0. + # Gets sockets by counting unique socket ids. The grepping is done in any case to avoid matching comments. + CORESPERSOCKET=$(lscpu -p=cpu,socket | grep "^[0-9]\+,0" | sort | uniq | wc -l) + SOCKETS=$(lscpu -p=socket | grep -e "^[0-9]" | sort | uniq | wc -l) fi - N=`bc <<< "${CORESPERSOCKET}*${SOCKETS}"` + N=$((${CORESPERSOCKET}*${SOCKETS})) echo "${N}" } From c628d2979878efaeda5a4cabbea11b653c3e369d Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Tue, 9 Dec 2025 16:39:01 +0100 Subject: [PATCH 010/234] Integrate non-uniform InteractionSampler into CollisionContextTool Possibility to inject non-uniform MU(BC) distributions into the collision context creation. Distributions can come from ROOT file or CCDB and follow a format from EventSelectionQA (histogram hBcTVX). Example: ``` --nontrivial-mu-distribution ccdb://http://ccdb-test.cern.ch:8080/GLO/CALIB/EVSELQA/HBCTVX' ``` --- .../simulation/src/InteractionSampler.cxx | 3 + Steer/src/CollisionContextTool.cxx | 79 ++++++++++++++++++- 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/DataFormats/simulation/src/InteractionSampler.cxx b/DataFormats/simulation/src/InteractionSampler.cxx index 61b2c4f61bc08..f3ece5c51f90b 100644 --- a/DataFormats/simulation/src/InteractionSampler.cxx +++ b/DataFormats/simulation/src/InteractionSampler.cxx @@ -202,6 +202,9 @@ bool NonUniformMuInteractionSampler::setBCIntensityScales(const TH1F& hist) std::vector NonUniformMuInteractionSampler::determineBCIntensityScalesFromHistogram(const TH1F& hist) { + if (mInteractingBCs.size() == 0) { + LOG(error) << " Initialize bunch crossing scheme before assigning scales"; + } std::vector scales; // we go through the BCs and query the count from histogram for (auto bc : mInteractingBCs) { diff --git a/Steer/src/CollisionContextTool.cxx b/Steer/src/CollisionContextTool.cxx index a6c2b0e62e0ca..b884909aedd9d 100644 --- a/Steer/src/CollisionContextTool.cxx +++ b/Steer/src/CollisionContextTool.cxx @@ -29,6 +29,9 @@ #include "DataFormatsParameters/GRPLHCIFData.h" #include "SimConfig/SimConfig.h" #include +#include +#include +#include // // Created by Sandro Wenzel on 13.07.21. @@ -64,6 +67,8 @@ struct Options { // This is useful when someone else is creating the contexts (MC-data embedding) and we // merely want to pass these through. If this is given, we simply take the timeframe ID, number of orbits // and copy the right amount of timeframes into the destination folder (implies individualTFextraction) + std::string nontrivial_mu_distribution = ""; // path to fetch a non-uniform MC(BC) distribution for the interaction sampler + // can be: (a) ccdb, (b) a ROOT file with the histogram included }; enum class InteractionLockMode { @@ -72,6 +77,28 @@ enum class InteractionLockMode { MINTIMEDISTANCE }; +struct CcdbUrl { + std::string server; // may include http:// or https:// + std::string port; // empty if none + std::string fullPath; // everything after server[:port]/ +}; + +std::optional parseCcdbRegex(const std::string& url) +{ + static const std::regex re( + R"(^(?:ccdb://)(https?://[^/:]+|[^/:]+)(?::(\d+))?/(.+)$)"); + std::smatch m; + if (!std::regex_match(url, m, re)) { + return std::nullopt; + } + + CcdbUrl out; + out.server = m[1].str(); // server (may include http:// or https://) + out.port = m[2].str(); // optional port + out.fullPath = m[3].str(); // remainder + return out; +} + struct InteractionSpec { std::string name; // name (prefix for transport simulation); may also serve as unique identifier float interactionRate; @@ -216,8 +243,8 @@ bool parseOptions(int argc, char* argv[], Options& optvalues) "timestamp", bpo::value(&optvalues.timestamp)->default_value(-1L), "Timestamp for CCDB queries / anchoring")( "extract-per-timeframe", bpo::value(&optvalues.individualTFextraction)->default_value(""), "Extract individual timeframe contexts. Format required: time_frame_prefix[:comma_separated_list_of_signals_to_offset]")( - "import-external", bpo::value(&optvalues.external_path)->default_value(""), - "Take collision contexts (per timeframe) from external files for instance for data-anchoring use-case. Needs timeframeID and number of orbits to be given as well."); + "import-external", bpo::value(&optvalues.external_path)->default_value(""), "Take collision contexts (per timeframe) from external files for instance for data-anchoring use-case. Needs timeframeID and number of orbits to be given as well.")( + "nontrivial-mu-distribution", bpo::value(&optvalues.nontrivial_mu_distribution)->default_value(""), "Distribution for MU(BC)"); options.add_options()("help,h", "Produce help message."); @@ -397,6 +424,46 @@ int main(int argc, char* argv[]) auto mode = ispecs[id].syncmode; if (mode == InteractionLockMode::NOLOCK) { auto sampler = std::make_unique(); + TH1F* mu_hist = nullptr; + + // we check if there is a realistic bunch crossing distribution available + const auto& mu_distr_source = options.nontrivial_mu_distribution; + if (mu_distr_source.size() > 0) { + if (mu_distr_source.find("ccdb") == 0) { + auto ccdb_info_wrapper = parseCcdbRegex(mu_distr_source); + if (!ccdb_info_wrapper.has_value()) { + LOG(error) << "Could not parse CCDB path for mu(bc) distribution"; + } else { + auto& ccdb_info = ccdb_info_wrapper.value(); + + // for now construct a specific CCDBManager for this query + o2::ccdb::CCDBManagerInstance ccdb_inst(ccdb_info.server + std::string(":") + ccdb_info.port); + ccdb_inst.setFatalWhenNull(false); + auto local_hist = ccdb_inst.getForTimeStamp(ccdb_info.fullPath, options.timestamp); + if (local_hist) { + mu_hist = (TH1F*)(local_hist->Clone("h2")); // we need to clone since ownership of local_hist is with TFile + } else { + LOG(warn) << "No mu(bc) distribution found on CCDB. Using uniform one"; + } + } + } else { + // we interpret the file as a ROOT file and open it to extract the wanted histogram + auto mudistr_file = TFile::Open(mu_distr_source.c_str(), "OPEN"); + if (mudistr_file && !mudistr_file->IsZombie()) { + auto local_hist = mudistr_file->Get("hBcTVX"); + mu_hist = (TH1F*)(local_hist->Clone("h2")); // we need to clone since ownership of local_hist is with TFile + mudistr_file->Close(); + } + } + if (mu_hist) { + LOG(info) << "Found an external mu distribution with mean BC value " << mu_hist->GetMean(); + + // do some checks + + // reset to correct interaction Sampler type + sampler.reset(new o2::steer::NonUniformMuInteractionSampler()); + } + } // for debug purposes: allows to instantiate trivial sampler if (const char* env = getenv("ALICEO2_ENFORCE_TRIVIAL_BC_SAMPLER")) { @@ -418,11 +485,17 @@ int main(int argc, char* argv[]) if (!options.bcpatternfile.empty()) { setBCFillingHelper(*sampler, options.bcpatternfile); } + sampler->init(); + if (auto sampler_cast = dynamic_cast(sampler.get())) { + if (mu_hist) { + sampler_cast->setBCIntensityScales(*mu_hist); + } + } + o2::InteractionTimeRecord record; // this loop makes sure that the first collision is within the range of orbits asked (if noEmptyTF is enabled) do { sampler->setFirstIR(o2::InteractionRecord(options.firstBC, orbitstart)); - sampler->init(); record = sampler->generateCollisionTime(); } while (options.noEmptyTF && usetimeframelength && record.orbit >= orbitstart + orbits_total); int count = 0; From deff3d8eb8595991c19dd4e5b166980c08c1ba98 Mon Sep 17 00:00:00 2001 From: Matthias Kleiner <48915672+matthias-kleiner@users.noreply.github.com> Date: Sat, 13 Dec 2025 19:26:36 +0100 Subject: [PATCH 011/234] TPC: Use CTP as fallback if no IDCs are available (#14919) * TPC: Use CTP as fallback if no IDCs are available * Dont update map as only the lumi is updated --- .../TPCCalibration/CorrectionMapsLoader.h | 1 + .../calibration/src/CorrectionMapsLoader.cxx | 37 +++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CorrectionMapsLoader.h b/Detectors/TPC/calibration/include/TPCCalibration/CorrectionMapsLoader.h index a907b83fe49bf..5a11ce3ea24e5 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CorrectionMapsLoader.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CorrectionMapsLoader.h @@ -79,6 +79,7 @@ class CorrectionMapsLoader : public o2::gpu::CorrectionMapsHelper float mInstLumiCTPFactor = 1.0; // multiplicative factor for inst. lumi int mLumiCTPSource = 0; // 0: main, 1: alternative CTP lumi source std::unique_ptr mCorrMapMShape{nullptr}; + bool mIDC2CTPFallbackActive = false; // flag indicating that fallback from IDC to CTP scaling is active #endif }; diff --git a/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx b/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx index 0e4a5e2a73df4..e9d7474699ce2 100644 --- a/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx +++ b/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx @@ -53,6 +53,37 @@ void CorrectionMapsLoader::extractCCDBInputs(ProcessingContext& pc) o2::ctp::LumiInfo lumiObj; static o2::ctp::LumiInfo lumiPrev; + if (getLumiScaleType() == 2 || mIDC2CTPFallbackActive) { + float tpcScaler = pc.inputs().get("tpcscaler"); + // check if tpcScaler is valid and CTP fallback is allowed + if (tpcScaler == -1.f) { + const bool canUseCTPScaling = mCorrMap && mCorrMapRef && mCorrMap->isIDCSet() && mCorrMapRef->isIDCSet() && mCorrMap->isLumiSet() && mCorrMapRef->isLumiSet(); + if (canUseCTPScaling) { + LOGP(info, "Invalid TPC scaler value {} received for IDC-based scaling! Using CTP fallback", tpcScaler); + mIDC2CTPFallbackActive = true; + setMeanLumi(mCorrMap->getLumi(), false); + setMeanLumiRef(mCorrMapRef->getLumi()); + setLumiScaleType(1); + } else if (mCorrMap) { + // CTP scaling is not possible, dont do any scaling to avoid applying wrong corrections + const float storedIDC = mCorrMap->getIDC(); + LOGP(warning, "Invalid TPC scaler value {} received for IDC-based scaling! CTP fallback not possible, using stored IDC of {} from the map to avoid applying wrong corrections", tpcScaler, storedIDC); + setInstLumi(storedIDC); + } + } else { + if (mIDC2CTPFallbackActive) { + // reset back to normal operation + LOGP(info, "Valid TPC scaler value {} received, switching back to IDC-based scaling", tpcScaler); + mIDC2CTPFallbackActive = false; + setMeanLumi(mCorrMap->getIDC(), false); + setMeanLumiRef(mCorrMapRef->getIDC()); + setLumiScaleType(2); + } + // correct IDC received + setInstLumi(tpcScaler); + } + } + if (getLumiCTPAvailable() && mInstCTPLumiOverride <= 0.) { if (pc.inputs().get>("CTPLumi").size() == sizeof(o2::ctp::LumiInfo)) { lumiPrev = lumiObj = pc.inputs().get("CTPLumi"); @@ -67,10 +98,7 @@ void CorrectionMapsLoader::extractCCDBInputs(ProcessingContext& pc) setInstLumi(getInstLumiCTP()); } } - if (getLumiScaleType() == 2) { - float tpcScaler = pc.inputs().get("tpcscaler"); - setInstLumi(tpcScaler); - } + if (getUseMShapeCorrection()) { LOGP(info, "Setting M-Shape map"); const auto mapMShape = pc.inputs().get("mshape"); @@ -317,6 +345,7 @@ void CorrectionMapsLoader::copySettings(const CorrectionMapsLoader& src) mLumiCTPSource = src.mLumiCTPSource; mLumiScaleMode = src.mLumiScaleMode; mScaleInverse = src.getScaleInverse(); + mIDC2CTPFallbackActive = src.mIDC2CTPFallbackActive; } void CorrectionMapsLoader::updateInverse() From 519b2f7b7d84edd893cc28a55569497fd6d6fdf2 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 30 Oct 2025 16:57:23 +0100 Subject: [PATCH 012/234] GPU: Unify applying settings for sync reco between standalone and GPUWorkflow --- GPU/GPUTracking/Global/GPUChainTracking.cxx | 14 ++++++++++ GPU/GPUTracking/Global/GPUChainTracking.h | 3 ++ GPU/GPUTracking/Interface/GPUO2Interface.cxx | 5 ++++ GPU/GPUTracking/Interface/GPUO2Interface.h | 3 ++ .../Standalone/Benchmark/standalone.cxx | 28 ++++++------------- GPU/Workflow/src/GPUWorkflowSpec.cxx | 11 ++------ 6 files changed, 36 insertions(+), 28 deletions(-) diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index 0e7d4bc4f436e..8a0d45a33ca93 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -1007,3 +1007,17 @@ void GPUChainTracking::SetO2Propagator(const o2::base::Propagator* prop) GPUFatal("GPU magnetic field for propagator requested, but received an O2 propagator without GPU field"); } } + +void GPUChainTracking::ApplySyncSettings(GPUSettingsProcessing& proc, GPUSettingsRec& rec, GPUDataTypes::RecoStepField& steps, bool syncMode, int32_t dEdxMode) +{ + if (syncMode) { + rec.useMatLUT = false; + rec.tpc.rebuildTrackMaxNonIntCov = 0.f; + } + if (proc.rtc.optSpecialCode == -1) { + proc.rtc.optSpecialCode = syncMode; + } + if (dEdxMode != -2) { + steps.setBits(GPUDataTypes::RecoStep::TPCdEdx, dEdxMode == -1 ? !syncMode : dEdxMode > 0); + } +} diff --git a/GPU/GPUTracking/Global/GPUChainTracking.h b/GPU/GPUTracking/Global/GPUChainTracking.h index 4b07aadfad357..7d70e0b667946 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.h +++ b/GPU/GPUTracking/Global/GPUChainTracking.h @@ -66,6 +66,8 @@ struct GPUNewCalibValues; struct GPUTriggerOutputs; struct CfFragment; class GPUTPCClusterFinder; +struct GPUSettingsProcessing; +struct GPUSettingsRec; class GPUChainTracking : public GPUChain { @@ -86,6 +88,7 @@ class GPUChainTracking : public GPUChain void ClearErrorCodes(bool cpuOnly = false); int32_t DoQueuedUpdates(int32_t stream, bool updateSlave = true); // Forces doing queue calib updates, don't call when you are not sure you are allowed to do so! bool QARanForTF() const { return mFractionalQAEnabled; } + static void ApplySyncSettings(GPUSettingsProcessing& proc, GPUSettingsRec& rec, GPUDataTypes::RecoStepField& steps, bool syncMode, int32_t dEdxMode = -2); // Structures for input and output data GPUTrackingInOutPointers& mIOPtrs; diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.cxx b/GPU/GPUTracking/Interface/GPUO2Interface.cxx index d04db5e9bf271..95a57a4b17c4b 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.cxx +++ b/GPU/GPUTracking/Interface/GPUO2Interface.cxx @@ -268,3 +268,8 @@ void GPUO2Interface::UseGPUPolynomialFieldInPropagator(o2::base::Propagator* pro { prop->setGPUField(&mCtx[0].mRec->GetParam().polynomialField); } + +void GPUO2Interface::ApplySyncSettings(GPUSettingsProcessing& proc, GPUSettingsRec& rec, GPUDataTypes::RecoStepField& steps, bool syncMode, int32_t dEdxMode) +{ + GPUChainTracking::ApplySyncSettings(proc, rec, steps, syncMode, dEdxMode); +} diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.h b/GPU/GPUTracking/Interface/GPUO2Interface.h index 00c72cc5e3359..3b4dde2cb0f96 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.h +++ b/GPU/GPUTracking/Interface/GPUO2Interface.h @@ -56,6 +56,8 @@ struct GPUInterfaceInputUpdate; struct GPUTrackingOutputs; struct GPUConstantMem; struct GPUNewCalibValues; +struct GPUSettingsProcessing; +struct GPUSettingsRec; struct GPUO2Interface_processingContext; struct GPUO2Interface_Internals; @@ -80,6 +82,7 @@ class GPUO2Interface // Updates all calibration objects that are != nullptr in newCalib int32_t UpdateCalibration(const GPUCalibObjectsConst& newCalib, const GPUNewCalibValues& newVals, uint32_t iThread = 0); + static void ApplySyncSettings(GPUSettingsProcessing& proc, GPUSettingsRec& rec, GPUDataTypes::RecoStepField& steps, bool syncMode, int32_t dEdxMode = -2); int32_t registerMemoryForGPU(const void* ptr, size_t size); int32_t unregisterMemoryForGPU(const void* ptr); diff --git a/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx b/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx index 857803d913372..1b3603a226af0 100644 --- a/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx +++ b/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx @@ -377,9 +377,6 @@ int32_t SetupReconstruction() } else if (chainTracking->GetTRDGeometry() == nullptr) { steps.steps.setBits(GPUDataTypes::RecoStep::TRDTracking, false); } - if (configStandalone.rundEdx != -1) { - steps.steps.setBits(GPUDataTypes::RecoStep::TPCdEdx, configStandalone.rundEdx > 0); - } if (configStandalone.runCompression != -1) { steps.steps.setBits(GPUDataTypes::RecoStep::TPCCompression, configStandalone.runCompression > 0); } @@ -434,23 +431,15 @@ int32_t SetupReconstruction() } } - bool runAsyncQA = procSet.runQA && !configStandalone.testSyncAsyncQcInSync; - if (configStandalone.testSyncAsync || configStandalone.testSync) { - // Set settings for synchronous - if (configStandalone.rundEdx == -1) { - steps.steps.setBits(GPUDataTypes::RecoStep::TPCdEdx, 0); - } - recSet.useMatLUT = false; - if (configStandalone.testSyncAsync) { - procSet.eventDisplay = nullptr; - if (!configStandalone.testSyncAsyncQcInSync) { - procSet.runQA = false; - } + // Set settings for synchronous + GPUChainTracking::ApplySyncSettings(procSet, recSet, steps.steps, configStandalone.testSyncAsync || configStandalone.testSync, configStandalone.rundEdx); + int32_t runAsyncQA = procSet.runQA && !configStandalone.testSyncAsyncQcInSync ? procSet.runQA : 0; + if (configStandalone.testSyncAsync) { + procSet.eventDisplay = nullptr; + if (!configStandalone.testSyncAsyncQcInSync) { + procSet.runQA = false; } } - if (configStandalone.proc.rtc.optSpecialCode == -1) { - configStandalone.proc.rtc.optSpecialCode = configStandalone.testSyncAsync || configStandalone.testSync; - } rec->SetSettings(&grp, &recSet, &procSet, &steps); if (configStandalone.proc.doublePipeline) { @@ -470,13 +459,12 @@ int32_t SetupReconstruction() procSet.runQA = runAsyncQA; procSet.eventDisplay = eventDisplay.get(); procSet.runCompressionStatistics = 0; - procSet.rtc.optSpecialCode = 0; if (recSet.tpc.rejectionStrategy >= GPUSettings::RejectionStrategyB) { procSet.tpcInputWithClusterRejection = 1; } recSet.tpc.disableRefitAttachment = 0xFF; recSet.maxTrackQPtB5 = CAMath::Min(recSet.maxTrackQPtB5, recSet.tpc.rejectQPtB5); - recSet.useMatLUT = true; + GPUChainTracking::ApplySyncSettings(procSet, recSet, steps.steps, false, configStandalone.rundEdx); recAsync->SetSettings(&grp, &recSet, &procSet, &steps); } diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index fb1d489a8479d..ca929bb025f80 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -185,20 +185,15 @@ void GPURecoWorkflowSpec::init(InitContext& ic) } } mConfig->configInterface.outputToExternalBuffers = true; - if (mConfParam->synchronousProcessing) { - mConfig->configReconstruction.useMatLUT = false; - } - if (mConfig->configProcessing.rtc.optSpecialCode == -1) { - mConfig->configProcessing.rtc.optSpecialCode = mConfParam->synchronousProcessing; - } + const bool runTracking = mSpecConfig.outputTracks || mSpecConfig.outputCompClustersRoot || mSpecConfig.outputCompClustersFlat; + GPUO2Interface::ApplySyncSettings(mConfig->configProcessing, mConfig->configReconstruction, mConfig->configWorkflow.steps, mConfParam->synchronousProcessing, runTracking ? mConfParam->rundEdx : -2); // Configure the "GPU workflow" i.e. which steps we run on the GPU (or CPU) - if (mSpecConfig.outputTracks || mSpecConfig.outputCompClustersRoot || mSpecConfig.outputCompClustersFlat) { + if (runTracking) { mConfig->configWorkflow.steps.set(GPUDataTypes::RecoStep::TPCConversion, GPUDataTypes::RecoStep::TPCSectorTracking, GPUDataTypes::RecoStep::TPCMerging); mConfig->configWorkflow.outputs.set(GPUDataTypes::InOutType::TPCMergedTracks); - mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCdEdx, mConfParam->rundEdx == -1 ? !mConfParam->synchronousProcessing : mConfParam->rundEdx); } if (mSpecConfig.outputCompClustersRoot || mSpecConfig.outputCompClustersFlat) { mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCCompression, true); From d6d20b4ec4049593fbe5d49b9bc667976ceaf98c Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 11 Dec 2025 20:56:56 +0100 Subject: [PATCH 013/234] GPU DataTypes / QA: Clean up some data types / enums --- .../DataFormatsTRD/RecoInputContainer.h | 2 +- .../include/ITStracking/TrackingInterface.h | 2 +- .../include/ITSWorkflow/RecoWorkflow.h | 4 +- .../include/ITSWorkflow/TrackerSpec.h | 12 ++- .../ITSMFT/ITS/workflow/src/RecoWorkflow.cxx | 2 +- .../ITSMFT/ITS/workflow/src/TrackerSpec.cxx | 4 +- .../ITS/workflow/src/its-reco-workflow.cxx | 2 +- .../reconstruction/test/testGPUCATracking.cxx | 10 +-- Detectors/TPC/workflow/src/ZSSpec.cxx | 2 +- .../workflow/src/TRDGlobalTrackingSpec.cxx | 4 +- .../include/TRKWorkflow/RecoWorkflow.h | 4 +- .../include/TRKWorkflow/TrackerSpec.h | 8 +- .../ALICE3/TRK/workflow/src/RecoWorkflow.cxx | 4 +- .../ALICE3/TRK/workflow/src/TrackerSpec.cxx | 4 +- .../TRK/workflow/src/trk-reco-workflow.cxx | 2 +- .../include/ITS3Workflow/RecoWorkflow.h | 6 +- .../include/ITS3Workflow/TrackerSpec.h | 12 ++- .../ITS3/workflow/src/RecoWorkflow.cxx | 2 +- .../ITS3/workflow/src/TrackerSpec.cxx | 4 +- .../ITS3/workflow/src/its3-reco-workflow.cxx | 2 +- GPU/GPUTracking/Base/GPUConstantMem.h | 2 +- GPU/GPUTracking/Base/GPUGeneralKernels.h | 9 ++- GPU/GPUTracking/Base/GPUParam.cxx | 4 +- GPU/GPUTracking/Base/GPUReconstruction.cxx | 10 +-- GPU/GPUTracking/Base/GPUReconstruction.h | 14 ++-- GPU/GPUTracking/Base/GPUReconstructionCPU.cxx | 14 ++-- .../Base/GPUReconstructionCPUKernels.h | 4 +- .../Base/GPUReconstructionConvert.cxx | 2 +- .../Base/GPUReconstructionIncludes.h | 2 +- .../Base/GPUReconstructionLibrary.cxx | 10 +-- .../Base/GPUReconstructionProcessing.h | 12 +-- .../Base/GPUReconstructionTimeframe.h | 2 +- GPU/GPUTracking/CMakeLists.txt | 13 ++- .../DataCompression/GPUTPCCompression.cxx | 6 +- .../GPUTPCCompressionKernels.h | 2 +- .../GPUTPCDecompressionKernels.h | 2 +- GPU/GPUTracking/DataTypes/GPUConfigDump.cxx | 2 +- ...PUDataTypes.cxx => GPUDataTypesConfig.cxx} | 10 +-- .../DataTypes/GPUDataTypesConfig.h | 80 +++++++++++++++++++ .../{GPUDataTypes.h => GPUDataTypesIO.h} | 66 +++------------ GPU/GPUTracking/DataTypes/GPUDataTypesQA.h | 42 ++++++++++ .../DataTypes/GPUO2ConfigurableParam.cxx | 4 +- GPU/GPUTracking/DataTypes/GPUSettings.h | 4 +- GPU/GPUTracking/Global/GPUChain.cxx | 12 +-- GPU/GPUTracking/Global/GPUChain.h | 12 +-- GPU/GPUTracking/Global/GPUChainITS.cxx | 2 +- GPU/GPUTracking/Global/GPUChainTracking.cxx | 73 +++++++++-------- GPU/GPUTracking/Global/GPUChainTracking.h | 5 +- .../Global/GPUChainTrackingClusterizer.cxx | 10 +-- .../GPUChainTrackingDebugAndProfiling.cxx | 2 +- .../Global/GPUChainTrackingTransformation.cxx | 4 +- GPU/GPUTracking/Global/GPUErrors.cxx | 2 +- .../Global/GPUTrackingInputProvider.cxx | 6 +- GPU/GPUTracking/Interface/GPUO2Interface.cxx | 8 +- GPU/GPUTracking/Interface/GPUO2Interface.h | 5 +- .../Interface/GPUO2InterfaceConfiguration.cxx | 2 +- .../Interface/GPUO2InterfaceConfiguration.h | 2 +- .../Interface/GPUO2InterfaceDisplay.h | 2 +- GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx | 8 +- GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.h | 2 +- .../Merger/GPUTPCGlobalDebugSortKernels.h | 2 +- .../Refit/GPUTrackingRefitKernel.h | 2 +- .../SectorTracker/GPUTPCCreateOccupancyMap.h | 2 +- .../SectorTracker/GPUTPCCreateTrackingData.h | 2 +- .../GPUTPCExtrapolationTracking.cxx | 26 +++--- .../GPUTPCExtrapolationTracking.h | 4 +- .../SectorTracker/GPUTPCNeighboursCleaner.h | 2 +- .../SectorTracker/GPUTPCNeighboursFinder.h | 2 +- .../GPUTPCSectorDebugSortKernels.h | 2 +- .../SectorTracker/GPUTPCStartHitsFinder.h | 2 +- .../SectorTracker/GPUTPCStartHitsSorter.h | 2 +- .../SectorTracker/GPUTPCTracker.cxx | 10 +-- .../SectorTracker/GPUTPCTrackletConstructor.h | 2 +- .../SectorTracker/GPUTPCTrackletSelector.h | 2 +- .../Standalone/Benchmark/standalone.cxx | 76 +++++++++--------- .../TPCClusterFinder/GPUTPCCFChainContext.h | 2 +- .../GPUTPCCFChargeMapFiller.h | 4 +- .../GPUTPCCFCheckPadBaseline.h | 4 +- .../TPCClusterFinder/GPUTPCCFClusterizer.h | 4 +- .../TPCClusterFinder/GPUTPCCFDecodeZS.h | 8 +- .../TPCClusterFinder/GPUTPCCFDeconvolution.h | 4 +- .../TPCClusterFinder/GPUTPCCFGather.h | 4 +- .../GPUTPCCFMCLabelFlattener.h | 4 +- .../GPUTPCCFNoiseSuppression.h | 4 +- .../TPCClusterFinder/GPUTPCCFPeakFinder.h | 4 +- .../GPUTPCCFStreamCompaction.h | 4 +- .../TPCClusterFinder/GPUTPCClusterFinder.cxx | 16 ++-- .../TPCClusterFinder/GPUTPCClusterFinder.h | 2 +- .../GPUTPCNNClusterizerKernels.h | 4 +- .../TRDTracking/GPUTRDTrackerKernels.h | 2 +- .../TRDTracking/macros/run_trd_tracker.C | 4 +- GPU/GPUTracking/dEdx/GPUdEdx.h | 1 + GPU/GPUTracking/display/GPUDisplay.h | 1 + .../display/render/GPUDisplayDraw.cxx | 3 +- GPU/GPUTracking/qa/GPUQA.h | 22 +---- .../GPUWorkflowHelper/GPUWorkflowHelper.h | 2 +- GPU/Workflow/src/GPUWorkflowInternal.h | 2 +- GPU/Workflow/src/GPUWorkflowPipeline.cxx | 2 +- GPU/Workflow/src/GPUWorkflowSpec.cxx | 45 ++++++----- doc/data/2021-01-o2_prs.json | 4 +- 100 files changed, 462 insertions(+), 397 deletions(-) rename GPU/GPUTracking/DataTypes/{GPUDataTypes.cxx => GPUDataTypesConfig.cxx} (73%) create mode 100644 GPU/GPUTracking/DataTypes/GPUDataTypesConfig.h rename GPU/GPUTracking/DataTypes/{GPUDataTypes.h => GPUDataTypesIO.h} (74%) create mode 100644 GPU/GPUTracking/DataTypes/GPUDataTypesQA.h diff --git a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RecoInputContainer.h b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RecoInputContainer.h index 353f635306e68..032dd4162a785 100644 --- a/DataFormats/Detectors/TRD/include/DataFormatsTRD/RecoInputContainer.h +++ b/DataFormats/Detectors/TRD/include/DataFormatsTRD/RecoInputContainer.h @@ -27,7 +27,7 @@ #include "Framework/InputRecord.h" #include "SimulationDataFormat/MCTruthContainer.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include #include diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingInterface.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingInterface.h index d31b1f11a4983..a882ca9b779c4 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingInterface.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingInterface.h @@ -24,7 +24,7 @@ #include "DataFormatsITSMFT/TopologyDictionary.h" #include "DataFormatsCalibration/MeanVertexObject.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include "GPUO2ExternalUser.h" #include "GPUChainITS.h" diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h index 011ee6b88ff6f..90b38acb34a95 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h @@ -16,7 +16,7 @@ #include "Framework/WorkflowSpec.h" #include "ITStracking/Configuration.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesConfig.h" namespace o2 { @@ -28,7 +28,7 @@ namespace reco_workflow framework::WorkflowSpec getWorkflow(bool useMC, bool useCMtracker, TrackingMode::Type trmode, const bool overrideBeamPosition = false, bool upstreamDigits = false, bool upstreamClusters = false, bool disableRootOutput = false, bool useGeom = false, int useTrig = 0, - bool useGPUWF = false, o2::gpu::GPUDataTypes::DeviceType dType = o2::gpu::GPUDataTypes::DeviceType::CPU); + bool useGPUWF = false, o2::gpu::gpudatatypes::DeviceType dType = o2::gpu::gpudatatypes::DeviceType::CPU); } } // namespace its diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackerSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackerSpec.h index ee5ba4d5cc61c..01eb7cb7b69aa 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackerSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackerSpec.h @@ -23,11 +23,17 @@ #include "ITStracking/TrackingInterface.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesConfig.h" #include "DetectorsBase/GRPGeomHelper.h" #include "TStopwatch.h" +namespace o2::gpu +{ +class GPUReconstruction; +class GPUChainITS; +} // namespace o2::gpu + namespace o2::its { @@ -39,7 +45,7 @@ class TrackerDPL : public framework::Task int trgType, const TrackingMode::Type trMode = TrackingMode::Unset, const bool overrBeamEst = false, - o2::gpu::GPUDataTypes::DeviceType dType = o2::gpu::GPUDataTypes::DeviceType::CPU); + o2::gpu::gpudatatypes::DeviceType dType = o2::gpu::gpudatatypes::DeviceType::CPU); ~TrackerDPL() override = default; void init(framework::InitContext& ic) final; void run(framework::ProcessingContext& pc) final; @@ -57,7 +63,7 @@ class TrackerDPL : public framework::Task TStopwatch mTimer; }; -framework::DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int useTrig, TrackingMode::Type trMode, const bool overrBeamEst = false, o2::gpu::GPUDataTypes::DeviceType dType = o2::gpu::GPUDataTypes::DeviceType::CPU); +framework::DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int useTrig, TrackingMode::Type trMode, const bool overrBeamEst = false, o2::gpu::gpudatatypes::DeviceType dType = o2::gpu::gpudatatypes::DeviceType::CPU); } // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx index f375eaf67c04f..368ca6909240f 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx @@ -38,7 +38,7 @@ framework::WorkflowSpec getWorkflow(bool useMC, bool useGeom, int useTrig, bool useGPUWF, - o2::gpu::GPUDataTypes::DeviceType dtype) + o2::gpu::gpudatatypes::DeviceType dtype) { framework::WorkflowSpec specs; if (!(upstreamDigits || upstreamClusters)) { diff --git a/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx index dbfd5edf839ae..12d84ca7ab6ad 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx @@ -28,7 +28,7 @@ TrackerDPL::TrackerDPL(std::shared_ptr gr, int trgType, const TrackingMode::Type trMode, const bool overrBeamEst, - o2::gpu::GPUDataTypes::DeviceType dType) : mGGCCDBRequest(gr), + o2::gpu::gpudatatypes::DeviceType dType) : mGGCCDBRequest(gr), mRecChain{o2::gpu::GPUReconstruction::CreateInstance(dType, true)}, mITSTrackingInterface{isMC, trgType, overrBeamEst} { @@ -78,7 +78,7 @@ void TrackerDPL::end() LOGF(info, "ITS CA-Tracker total timing: Cpu: %.3e Real: %.3e s in %d slots", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int trgType, TrackingMode::Type trMode, const bool overrBeamEst, o2::gpu::GPUDataTypes::DeviceType dType) +DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int trgType, TrackingMode::Type trMode, const bool overrBeamEst, o2::gpu::gpudatatypes::DeviceType dType) { std::vector inputs; diff --git a/Detectors/ITSMFT/ITS/workflow/src/its-reco-workflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/its-reco-workflow.cxx index 4b9053436d44c..4e1721f4194b0 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/its-reco-workflow.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/its-reco-workflow.cxx @@ -69,7 +69,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto trmode = configcontext.options().get("tracking-mode"); auto selTrig = configcontext.options().get("select-with-triggers"); auto useGpuWF = configcontext.options().get("use-gpu-workflow"); - auto gpuDevice = static_cast(configcontext.options().get("gpu-device")); + auto gpuDevice = static_cast(configcontext.options().get("gpu-device")); auto extDigits = configcontext.options().get("digits-from-upstream"); auto extClusters = configcontext.options().get("clusters-from-upstream"); auto disableRootOutput = configcontext.options().get("disable-root-output"); diff --git a/Detectors/TPC/reconstruction/test/testGPUCATracking.cxx b/Detectors/TPC/reconstruction/test/testGPUCATracking.cxx index 3e196fa9bb7cc..5c66e4635987f 100644 --- a/Detectors/TPC/reconstruction/test/testGPUCATracking.cxx +++ b/Detectors/TPC/reconstruction/test/testGPUCATracking.cxx @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(CATracking_test1) bool continuous = false; // time frame data v.s. triggered events GPUO2InterfaceConfiguration config; - config.configDeviceBackend.deviceType = GPUDataTypes::DeviceType::CPU; + config.configDeviceBackend.deviceType = gpudatatypes::DeviceType::CPU; config.configDeviceBackend.forceDeviceType = true; config.configProcessing.ompThreads = 4; // 4 threads if we run on the CPU, 1 = default, 0 = auto-detect @@ -69,10 +69,10 @@ BOOST_AUTO_TEST_CASE(CATracking_test1) config.configReconstruction.tpc.searchWindowDZDR = 2.5f; // Should always be 2.5 for looper-finding and/or continuous tracking config.configReconstruction.tpc.trackReferenceX = refX; - config.configWorkflow.steps.set(GPUDataTypes::RecoStep::TPCConversion, GPUDataTypes::RecoStep::TPCSectorTracking, - GPUDataTypes::RecoStep::TPCMerging, GPUDataTypes::RecoStep::TPCCompression, GPUDataTypes::RecoStep::TPCdEdx); - config.configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCClusters); - config.configWorkflow.outputs.set(GPUDataTypes::InOutType::TPCMergedTracks); + config.configWorkflow.steps.set(gpudatatypes::RecoStep::TPCConversion, gpudatatypes::RecoStep::TPCSectorTracking, + gpudatatypes::RecoStep::TPCMerging, gpudatatypes::RecoStep::TPCCompression, gpudatatypes::RecoStep::TPCdEdx); + config.configWorkflow.inputs.set(gpudatatypes::InOutType::TPCClusters); + config.configWorkflow.outputs.set(gpudatatypes::InOutType::TPCMergedTracks); std::unique_ptr fastTransform(TPCFastTransformHelperO2::instance()->create(0)); std::unique_ptr fastTransformHelper(new CorrectionMapsHelper()); diff --git a/Detectors/TPC/workflow/src/ZSSpec.cxx b/Detectors/TPC/workflow/src/ZSSpec.cxx index ccd59de42f000..c24647f6ae240 100644 --- a/Detectors/TPC/workflow/src/ZSSpec.cxx +++ b/Detectors/TPC/workflow/src/ZSSpec.cxx @@ -22,7 +22,7 @@ #include "DataFormatsTPC/ZeroSuppression.h" #include "DataFormatsTPC/Helpers.h" #include "DataFormatsTPC/Digit.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include "GPUHostDataTypes.h" #include "GPUO2InterfaceConfiguration.h" #include "TPCBase/Sector.h" diff --git a/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx b/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx index 598ce3c35c98c..9588888df5fc6 100644 --- a/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx +++ b/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx @@ -46,7 +46,7 @@ #include "GPUO2InterfaceConfiguration.h" #include "GPUO2InterfaceUtils.h" #include "GPUSettings.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include "GPUTRDDef.h" #include "GPUTRDTrack.h" #include "GPUTRDTrackletWord.h" @@ -103,7 +103,7 @@ void TRDGlobalTracking::updateTimeDependentParams(ProcessingContext& pc) mFlatGeo = std::make_unique(*geo); GPURecoStepConfiguration cfgRecoStep; - cfgRecoStep.steps = GPUDataTypes::RecoStep::NoRecoStep; + cfgRecoStep.steps = gpudatatypes::RecoStep::NoRecoStep; cfgRecoStep.inputs.clear(); cfgRecoStep.outputs.clear(); mRec = GPUReconstruction::CreateInstance("CPU", true); diff --git a/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/RecoWorkflow.h b/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/RecoWorkflow.h index 0c2489aa4b9c4..98d4154f11dd8 100644 --- a/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/RecoWorkflow.h +++ b/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/RecoWorkflow.h @@ -13,7 +13,7 @@ #define O2_TRK_RECOWORKFLOW_H #include "Framework/WorkflowSpec.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesConfig.h" namespace o2::trk { @@ -25,7 +25,7 @@ o2::framework::WorkflowSpec getWorkflow(bool useMC, bool upstreamClusters = false, bool disableRootOutput = false, bool useGPUWF = false, - o2::gpu::GPUDataTypes::DeviceType dType = o2::gpu::GPUDataTypes::DeviceType::CPU); + o2::gpu::gpudatatypes::DeviceType dType = o2::gpu::gpudatatypes::DeviceType::CPU); } } // namespace o2::trk diff --git a/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/TrackerSpec.h b/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/TrackerSpec.h index 3c82a4fd7b89d..dac1826e21cf6 100644 --- a/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/TrackerSpec.h +++ b/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/TrackerSpec.h @@ -20,7 +20,7 @@ #include "Framework/Task.h" #include "ITStracking/TrackingInterface.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesConfig.h" #include "DetectorsBase/GRPGeomHelper.h" @@ -33,7 +33,7 @@ class TrackerDPL : public framework::Task public: TrackerDPL(std::shared_ptr gr, bool isMC, - gpu::GPUDataTypes::DeviceType dType = gpu::GPUDataTypes::DeviceType::CPU); + gpu::gpudatatypes::DeviceType dType = gpu::gpudatatypes::DeviceType::CPU); ~TrackerDPL() override = default; void init(framework::InitContext& ic) final; void run(framework::ProcessingContext& pc) final; @@ -50,7 +50,7 @@ class TrackerDPL : public framework::Task TStopwatch mTimer; }; -framework::DataProcessorSpec getTrackerSpec(bool useMC, gpu::GPUDataTypes::DeviceType dType = gpu::GPUDataTypes::DeviceType::CPU); +framework::DataProcessorSpec getTrackerSpec(bool useMC, gpu::gpudatatypes::DeviceType dType = gpu::gpudatatypes::DeviceType::CPU); } // namespace o2::trk -#endif /* O2_TRK_TRACKERDPL */ \ No newline at end of file +#endif /* O2_TRK_TRACKERDPL */ diff --git a/Detectors/Upgrades/ALICE3/TRK/workflow/src/RecoWorkflow.cxx b/Detectors/Upgrades/ALICE3/TRK/workflow/src/RecoWorkflow.cxx index 3b2b44729b259..09d447a576e48 100644 --- a/Detectors/Upgrades/ALICE3/TRK/workflow/src/RecoWorkflow.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/workflow/src/RecoWorkflow.cxx @@ -21,11 +21,11 @@ framework::WorkflowSpec getWorkflow(bool useMC, bool upstreamClusters, bool disableRootOutput, bool useGPUWF, - o2::gpu::GPUDataTypes::DeviceType dtype) + o2::gpu::gpudatatypes::DeviceType dtype) { framework::WorkflowSpec specs; specs.emplace_back(o2::trk::getTrackerSpec(useMC, dtype)); return specs; } -} // namespace o2::trk::reco_workflow \ No newline at end of file +} // namespace o2::trk::reco_workflow diff --git a/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx b/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx index 4057bab3b948f..868a8acc0fc6e 100644 --- a/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx @@ -25,7 +25,7 @@ using Vertex = o2::dataformats::Vertex>; TrackerDPL::TrackerDPL(std::shared_ptr gr, bool isMC, - o2::gpu::GPUDataTypes::DeviceType dType) + o2::gpu::gpudatatypes::DeviceType dType) { // mITSTrackingInterface.setTrackingMode(trMode); } @@ -67,7 +67,7 @@ void TrackerDPL::endOfStream(EndOfStreamContext& ec) LOGF(info, "TRK CA-Tracker total timing: Cpu: %.3e Real: %.3e s in %d slots", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getTrackerSpec(bool useMC, o2::gpu::GPUDataTypes::DeviceType dType) +DataProcessorSpec getTrackerSpec(bool useMC, o2::gpu::gpudatatypes::DeviceType dType) { std::vector inputs; diff --git a/Detectors/Upgrades/ALICE3/TRK/workflow/src/trk-reco-workflow.cxx b/Detectors/Upgrades/ALICE3/TRK/workflow/src/trk-reco-workflow.cxx index 0f75d42710400..8f44b01da1c9c 100644 --- a/Detectors/Upgrades/ALICE3/TRK/workflow/src/trk-reco-workflow.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/workflow/src/trk-reco-workflow.cxx @@ -67,7 +67,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // Update the (declared) parameters if changed from the command line auto useMC = !configcontext.options().get("disable-mc"); auto useGpuWF = configcontext.options().get("use-gpu-workflow"); - auto gpuDevice = static_cast(configcontext.options().get("gpu-device")); + auto gpuDevice = static_cast(configcontext.options().get("gpu-device")); auto extDigits = configcontext.options().get("digits-from-upstream"); auto extClusters = configcontext.options().get("clusters-from-upstream"); auto disableRootOutput = configcontext.options().get("disable-root-output"); diff --git a/Detectors/Upgrades/ITS3/workflow/include/ITS3Workflow/RecoWorkflow.h b/Detectors/Upgrades/ITS3/workflow/include/ITS3Workflow/RecoWorkflow.h index 592a34d94a3ca..010e1cd0a8127 100644 --- a/Detectors/Upgrades/ITS3/workflow/include/ITS3Workflow/RecoWorkflow.h +++ b/Detectors/Upgrades/ITS3/workflow/include/ITS3Workflow/RecoWorkflow.h @@ -16,16 +16,14 @@ #include "Framework/WorkflowSpec.h" #include "ITStracking/Configuration.h" -#include "GPUO2Interface.h" -#include "GPUReconstruction.h" -#include "GPUChainITS.h" +#include "GPUDataTypesConfig.h" namespace o2::its3::reco_workflow { framework::WorkflowSpec getWorkflow(bool useMC, its::TrackingMode::Type trmode, - o2::gpu::GPUDataTypes::DeviceType dtype, + o2::gpu::gpudatatypes::DeviceType dtype, bool useGPUWorkflow, bool upstreamDigits, bool upstreamClusters, diff --git a/Detectors/Upgrades/ITS3/workflow/include/ITS3Workflow/TrackerSpec.h b/Detectors/Upgrades/ITS3/workflow/include/ITS3Workflow/TrackerSpec.h index 42f71b6ccebe0..66d58a5f5a92c 100644 --- a/Detectors/Upgrades/ITS3/workflow/include/ITS3Workflow/TrackerSpec.h +++ b/Detectors/Upgrades/ITS3/workflow/include/ITS3Workflow/TrackerSpec.h @@ -23,11 +23,17 @@ #include "ITS3Reconstruction/TrackingInterface.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesConfig.h" #include "DetectorsBase/GRPGeomHelper.h" #include "TStopwatch.h" +namespace o2::gpu +{ +class GPUReconstruction; +class GPUChainITS; +} // namespace o2::gpu + namespace o2::its3 { @@ -39,7 +45,7 @@ class TrackerDPL : public framework::Task int trgType, its::TrackingMode::Type trmode = its::TrackingMode::Unset, const bool overrBeamEst = false, - gpu::GPUDataTypes::DeviceType dType = gpu::GPUDataTypes::DeviceType::CPU); + gpu::gpudatatypes::DeviceType dType = gpu::gpudatatypes::DeviceType::CPU); ~TrackerDPL() override = default; TrackerDPL(const TrackerDPL&) = delete; TrackerDPL(TrackerDPL&&) = delete; @@ -63,7 +69,7 @@ class TrackerDPL : public framework::Task /// create a processor spec /// run ITS CA tracker -framework::DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int useTrig, its::TrackingMode::Type trMode, const bool overrBeamEst = false, gpu::GPUDataTypes::DeviceType dType = gpu::GPUDataTypes::DeviceType::CPU); +framework::DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int useTrig, its::TrackingMode::Type trMode, const bool overrBeamEst = false, gpu::gpudatatypes::DeviceType dType = gpu::gpudatatypes::DeviceType::CPU); } // namespace o2::its3 diff --git a/Detectors/Upgrades/ITS3/workflow/src/RecoWorkflow.cxx b/Detectors/Upgrades/ITS3/workflow/src/RecoWorkflow.cxx index 8a1c1ef73cf2b..004c3f6097167 100644 --- a/Detectors/Upgrades/ITS3/workflow/src/RecoWorkflow.cxx +++ b/Detectors/Upgrades/ITS3/workflow/src/RecoWorkflow.cxx @@ -26,7 +26,7 @@ static std::shared_ptr gTask; namespace o2::its3::reco_workflow { -framework::WorkflowSpec getWorkflow(bool useMC, its::TrackingMode::Type trmode, o2::gpu::GPUDataTypes::DeviceType dtype, bool useGPUWorkflow, +framework::WorkflowSpec getWorkflow(bool useMC, its::TrackingMode::Type trmode, o2::gpu::gpudatatypes::DeviceType dtype, bool useGPUWorkflow, bool upstreamDigits, bool upstreamClusters, bool disableRootOutput, bool useGeom, int useTrig, bool overrideBeamPosition) { framework::WorkflowSpec specs; diff --git a/Detectors/Upgrades/ITS3/workflow/src/TrackerSpec.cxx b/Detectors/Upgrades/ITS3/workflow/src/TrackerSpec.cxx index 216056153d095..0326c12f804e0 100644 --- a/Detectors/Upgrades/ITS3/workflow/src/TrackerSpec.cxx +++ b/Detectors/Upgrades/ITS3/workflow/src/TrackerSpec.cxx @@ -44,7 +44,7 @@ TrackerDPL::TrackerDPL(std::shared_ptr gr, int trgType, its::TrackingMode::Type trMode, const bool overrBeamEst, - o2::gpu::GPUDataTypes::DeviceType dType) : mGGCCDBRequest(gr), + o2::gpu::gpudatatypes::DeviceType dType) : mGGCCDBRequest(gr), mRecChain{o2::gpu::GPUReconstruction::CreateInstance(dType, true)}, mITS3TrackingInterface{isMC, trgType, overrBeamEst} { @@ -88,7 +88,7 @@ void TrackerDPL::endOfStream(EndOfStreamContext& ec) LOGF(info, "ITS3 CA-Tracker total timing: Cpu: %.3e Real: %.3e s in %d slots", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int trgType, its::TrackingMode::Type trMode, const bool overrBeamEst, o2::gpu::GPUDataTypes::DeviceType dType) +DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int trgType, its::TrackingMode::Type trMode, const bool overrBeamEst, o2::gpu::gpudatatypes::DeviceType dType) { std::vector inputs; inputs.emplace_back("compClusters", "ITS", "COMPCLUSTERS", 0, Lifetime::Timeframe); diff --git a/Detectors/Upgrades/ITS3/workflow/src/its3-reco-workflow.cxx b/Detectors/Upgrades/ITS3/workflow/src/its3-reco-workflow.cxx index e4c78b3323a5e..018ad807a974a 100644 --- a/Detectors/Upgrades/ITS3/workflow/src/its3-reco-workflow.cxx +++ b/Detectors/Upgrades/ITS3/workflow/src/its3-reco-workflow.cxx @@ -63,7 +63,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto beamPosOVerride = configcontext.options().get("ccdb-meanvertex-seed"); auto trmode = configcontext.options().get("tracking-mode"); auto selTrig = configcontext.options().get("select-with-triggers"); - auto gpuDevice = static_cast(configcontext.options().get("gpu-device")); + auto gpuDevice = static_cast(configcontext.options().get("gpu-device")); auto extDigits = configcontext.options().get("digits-from-upstream"); auto extClusters = configcontext.options().get("clusters-from-upstream"); auto disableRootOutput = configcontext.options().get("disable-root-output"); diff --git a/GPU/GPUTracking/Base/GPUConstantMem.h b/GPU/GPUTracking/Base/GPUConstantMem.h index c496151c3dfd0..efb83a7e874c8 100644 --- a/GPU/GPUTracking/Base/GPUConstantMem.h +++ b/GPU/GPUTracking/Base/GPUConstantMem.h @@ -17,7 +17,7 @@ #include "GPUTPCTracker.h" #include "GPUParam.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include "GPUErrors.h" #include "GPUTPCGMMerger.h" diff --git a/GPU/GPUTracking/Base/GPUGeneralKernels.h b/GPU/GPUTracking/Base/GPUGeneralKernels.h index eb816c91f5909..871cc21ee2bfa 100644 --- a/GPU/GPUTracking/Base/GPUGeneralKernels.h +++ b/GPU/GPUTracking/Base/GPUGeneralKernels.h @@ -16,7 +16,8 @@ #define GPUGENERALKERNELS_H #include "GPUDef.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" +#include "GPUDataTypesConfig.h" #if defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_COMPILEKERNELS) && !defined(GPUCA_GPUCODE_HOSTONLY) #if defined(__CUDACC__) @@ -79,7 +80,7 @@ class GPUKernelTemplate }; typedef GPUconstantref() GPUConstantMem processorType; - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::NoRecoStep; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::NoRecoStep; } GPUhdi() static processorType* Processor(GPUConstantMem& processors) { return &processors; @@ -94,7 +95,7 @@ class GPUKernelTemplate class GPUMemClean16 : public GPUKernelTemplate { public: - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::NoRecoStep; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::NoRecoStep; } template GPUd() static void Thread(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUsharedref() GPUSharedMemory& smem, processorType& processors, GPUglobalref() void* ptr, uint64_t size); }; @@ -103,7 +104,7 @@ class GPUMemClean16 : public GPUKernelTemplate class GPUitoa : public GPUKernelTemplate { public: - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::NoRecoStep; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::NoRecoStep; } template GPUd() static void Thread(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUsharedref() GPUSharedMemory& smem, processorType& processors, GPUglobalref() int32_t* ptr, uint64_t size); }; diff --git a/GPU/GPUTracking/Base/GPUParam.cxx b/GPU/GPUTracking/Base/GPUParam.cxx index 7095766e8512e..aa4c3c7671c93 100644 --- a/GPU/GPUTracking/Base/GPUParam.cxx +++ b/GPU/GPUTracking/Base/GPUParam.cxx @@ -18,7 +18,7 @@ #include "GPUCommonMath.h" #include "GPUCommonConstants.h" #include "GPUTPCGMPolynomialFieldManager.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include "GPUConstantMem.h" #include "DetectorsBase/Propagator.h" #include "GPUTPCGeometry.h" @@ -127,7 +127,7 @@ void GPUParam::UpdateSettings(const GPUSettingsGRP* g, const GPUSettingsProcessi UpdateRun3ClusterErrors(p->param.tpcErrorParamY, p->param.tpcErrorParamZ); } if (w) { - par.dodEdx = dodEdxEnabled = w->steps.isSet(GPUDataTypes::RecoStep::TPCdEdx); + par.dodEdx = dodEdxEnabled = w->steps.isSet(gpudatatypes::RecoStep::TPCdEdx); if (dodEdxEnabled && p && p->tpcDownscaledEdx != 0) { dodEdxEnabled = (rand() % 100) < p->tpcDownscaledEdx; } diff --git a/GPU/GPUTracking/Base/GPUReconstruction.cxx b/GPU/GPUTracking/Base/GPUReconstruction.cxx index cae7c5025609b..ef336526080b9 100644 --- a/GPU/GPUTracking/Base/GPUReconstruction.cxx +++ b/GPU/GPUTracking/Base/GPUReconstruction.cxx @@ -296,7 +296,7 @@ int32_t GPUReconstruction::InitPhaseBeforeDevice() if (!GetProcessingSettings().createO2Output || !IsGPU()) { mProcessingSettings->clearO2OutputFromGPU = false; } - if (!(mRecoSteps.stepsGPUMask & GPUDataTypes::RecoStep::TPCMerging)) { + if (!(mRecoSteps.stepsGPUMask & gpudatatypes::RecoStep::TPCMerging)) { mProcessingSettings->mergerSortTracks = false; } if (GetProcessingSettings().debugLevel > 3 || !IsGPU() || GetProcessingSettings().deterministicGPUReconstruction) { @@ -902,7 +902,7 @@ void GPUReconstruction::PopNonPersistentMemory(RecoStep step, uint64_t tag, cons GPUFatal("Tag mismatch when popping non persistent memory from stack : pop %s vs on stack %s", qTag2Str(tag).c_str(), qTag2Str(std::get<4>(mNonPersistentMemoryStack.back())).c_str()); } if (!proc && (GetProcessingSettings().debugLevel >= 3 || GetProcessingSettings().allocDebugLevel) && (IsGPU() || GetProcessingSettings().forceHostMemoryPoolSize)) { - printf("Allocated memory after %30s (%8s) (Stack %zu): ", GPUDataTypes::RECO_STEP_NAMES[getRecoStepNum(step, true)], qTag2Str(std::get<4>(mNonPersistentMemoryStack.back())).c_str(), mNonPersistentMemoryStack.size()); + printf("Allocated memory after %30s (%8s) (Stack %zu): ", gpudatatypes::RECO_STEP_NAMES[getRecoStepNum(step, true)], qTag2Str(std::get<4>(mNonPersistentMemoryStack.back())).c_str(), mNonPersistentMemoryStack.size()); PrintMemoryOverview(); printf("%76s", ""); PrintMemoryMax(); @@ -1074,8 +1074,8 @@ constexpr static inline int32_t getStepNum(T step, bool validCheck, int32_t N, c } // anonymous namespace } // namespace o2::gpu::internal -int32_t GPUReconstruction::getRecoStepNum(RecoStep step, bool validCheck) { return internal::getStepNum(step, validCheck, GPUDataTypes::N_RECO_STEPS, "Invalid Reco Step"); } -int32_t GPUReconstruction::getGeneralStepNum(GeneralStep step, bool validCheck) { return internal::getStepNum(step, validCheck, GPUDataTypes::N_GENERAL_STEPS, "Invalid General Step"); } +int32_t GPUReconstruction::getRecoStepNum(RecoStep step, bool validCheck) { return internal::getStepNum(step, validCheck, gpudatatypes::N_RECO_STEPS, "Invalid Reco Step"); } +int32_t GPUReconstruction::getGeneralStepNum(GeneralStep step, bool validCheck) { return internal::getStepNum(step, validCheck, gpudatatypes::N_GENERAL_STEPS, "Invalid General Step"); } void GPUReconstruction::RunPipelineWorker() { @@ -1222,7 +1222,7 @@ void GPUReconstruction::UpdateSettings(const GPUSettingsGRP* g, const GPUSetting mProcessingSettings->resetTimers = p->resetTimers; } GPURecoStepConfiguration* w = nullptr; - if (mRecoSteps.steps.isSet(GPUDataTypes::RecoStep::TPCdEdx)) { + if (mRecoSteps.steps.isSet(gpudatatypes::RecoStep::TPCdEdx)) { w = &mRecoSteps; } param().UpdateSettings(g, p, w, d); diff --git a/GPU/GPUTracking/Base/GPUReconstruction.h b/GPU/GPUTracking/Base/GPUReconstruction.h index fa636fa416538..b5dd29f940143 100644 --- a/GPU/GPUTracking/Base/GPUReconstruction.h +++ b/GPU/GPUTracking/Base/GPUReconstruction.h @@ -27,7 +27,7 @@ #include #include -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include "GPUMemoryResource.h" #include "GPUOutputControl.h" #include "GPUParam.h" @@ -83,12 +83,12 @@ class GPUReconstruction // General definitions constexpr static uint32_t NSECTORS = GPUCA_NSECTORS; - using GeometryType = GPUDataTypes::GeometryType; - using DeviceType = GPUDataTypes::DeviceType; - using RecoStep = GPUDataTypes::RecoStep; - using GeneralStep = GPUDataTypes::GeneralStep; - using RecoStepField = GPUDataTypes::RecoStepField; - using InOutTypeField = GPUDataTypes::InOutTypeField; + using GeometryType = gpudatatypes::GeometryType; + using DeviceType = gpudatatypes::DeviceType; + using RecoStep = gpudatatypes::RecoStep; + using GeneralStep = gpudatatypes::GeneralStep; + using RecoStepField = gpudatatypes::RecoStepField; + using InOutTypeField = gpudatatypes::InOutTypeField; static constexpr const char* const GEOMETRY_TYPE_NAMES[] = {"INVALID", "ALIROOT", "O2"}; #ifdef GPUCA_TPC_GEOMETRY_O2 diff --git a/GPU/GPUTracking/Base/GPUReconstructionCPU.cxx b/GPU/GPUTracking/Base/GPUReconstructionCPU.cxx index 3da96654b895d..409c28b8bf328 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionCPU.cxx +++ b/GPU/GPUTracking/Base/GPUReconstructionCPU.cxx @@ -262,7 +262,7 @@ int32_t GPUReconstructionCPU::RunChains() nEventReport += " (avergage of " + std::to_string(mStatNEvents) + " runs)"; } double kernelTotal = 0; - std::vector kernelStepTimes(GPUDataTypes::N_RECO_STEPS, 0.); + std::vector kernelStepTimes(gpudatatypes::N_RECO_STEPS, 0.); if (GetProcessingSettings().debugLevel >= 1) { for (uint32_t i = 0; i < mTimers.size(); i++) { @@ -296,17 +296,17 @@ int32_t GPUReconstructionCPU::RunChains() } } if (GetProcessingSettings().recoTaskTiming) { - for (int32_t i = 0; i < GPUDataTypes::N_RECO_STEPS; i++) { + for (int32_t i = 0; i < gpudatatypes::N_RECO_STEPS; i++) { if (kernelStepTimes[i] != 0. || mTimersRecoSteps[i].timerTotal.GetElapsedTime() != 0.) { printf("Execution Time: Step : %11s %38s Time: %'10.0f us %64s ( Total Time : %'14.0f us, CPU Time : %'14.0f us, %'7.2fx )\n", "Tasks", - GPUDataTypes::RECO_STEP_NAMES[i], kernelStepTimes[i] * 1000000 / mStatNEvents, "", mTimersRecoSteps[i].timerTotal.GetElapsedTime() * 1000000 / mStatNEvents, mTimersRecoSteps[i].timerCPU * 1000000 / mStatNEvents, mTimersRecoSteps[i].timerCPU / mTimersRecoSteps[i].timerTotal.GetElapsedTime()); + gpudatatypes::RECO_STEP_NAMES[i], kernelStepTimes[i] * 1000000 / mStatNEvents, "", mTimersRecoSteps[i].timerTotal.GetElapsedTime() * 1000000 / mStatNEvents, mTimersRecoSteps[i].timerCPU * 1000000 / mStatNEvents, mTimersRecoSteps[i].timerCPU / mTimersRecoSteps[i].timerTotal.GetElapsedTime()); } if (mTimersRecoSteps[i].bytesToGPU) { - printf("Execution Time: Step (D %8ux): %11s %38s Time: %'10.0f us (%8.3f GB/s - %'14zu bytes - %'14zu per call)\n", mTimersRecoSteps[i].countToGPU, "DMA to GPU", GPUDataTypes::RECO_STEP_NAMES[i], mTimersRecoSteps[i].timerToGPU.GetElapsedTime() * 1000000 / mStatNEvents, + printf("Execution Time: Step (D %8ux): %11s %38s Time: %'10.0f us (%8.3f GB/s - %'14zu bytes - %'14zu per call)\n", mTimersRecoSteps[i].countToGPU, "DMA to GPU", gpudatatypes::RECO_STEP_NAMES[i], mTimersRecoSteps[i].timerToGPU.GetElapsedTime() * 1000000 / mStatNEvents, mTimersRecoSteps[i].bytesToGPU / mTimersRecoSteps[i].timerToGPU.GetElapsedTime() * 1e-9, mTimersRecoSteps[i].bytesToGPU / mStatNEvents, mTimersRecoSteps[i].bytesToGPU / mTimersRecoSteps[i].countToGPU); } if (mTimersRecoSteps[i].bytesToHost) { - printf("Execution Time: Step (D %8ux): %11s %38s Time: %'10.0f us (%8.3f GB/s - %'14zu bytes - %'14zu per call)\n", mTimersRecoSteps[i].countToHost, "DMA to Host", GPUDataTypes::RECO_STEP_NAMES[i], mTimersRecoSteps[i].timerToHost.GetElapsedTime() * 1000000 / mStatNEvents, + printf("Execution Time: Step (D %8ux): %11s %38s Time: %'10.0f us (%8.3f GB/s - %'14zu bytes - %'14zu per call)\n", mTimersRecoSteps[i].countToHost, "DMA to Host", gpudatatypes::RECO_STEP_NAMES[i], mTimersRecoSteps[i].timerToHost.GetElapsedTime() * 1000000 / mStatNEvents, mTimersRecoSteps[i].bytesToHost / mTimersRecoSteps[i].timerToHost.GetElapsedTime() * 1e-9, mTimersRecoSteps[i].bytesToHost / mStatNEvents, mTimersRecoSteps[i].bytesToHost / mTimersRecoSteps[i].countToHost); } if (GetProcessingSettings().resetTimers) { @@ -319,9 +319,9 @@ int32_t GPUReconstructionCPU::RunChains() mTimersRecoSteps[i].countToHost = 0; } } - for (int32_t i = 0; i < GPUDataTypes::N_GENERAL_STEPS; i++) { + for (int32_t i = 0; i < gpudatatypes::N_GENERAL_STEPS; i++) { if (mTimersGeneralSteps[i].GetElapsedTime() != 0.) { - printf("Execution Time: General Step : %50s Time: %'10.0f us\n", GPUDataTypes::GENERAL_STEP_NAMES[i], mTimersGeneralSteps[i].GetElapsedTime() * 1000000 / mStatNEvents); + printf("Execution Time: General Step : %50s Time: %'10.0f us\n", gpudatatypes::GENERAL_STEP_NAMES[i], mTimersGeneralSteps[i].GetElapsedTime() * 1000000 / mStatNEvents); } } if (GetProcessingSettings().debugLevel >= 1) { diff --git a/GPU/GPUTracking/Base/GPUReconstructionCPUKernels.h b/GPU/GPUTracking/Base/GPUReconstructionCPUKernels.h index 7bf819a74e1b6..0c19941c40ea4 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionCPUKernels.h +++ b/GPU/GPUTracking/Base/GPUReconstructionCPUKernels.h @@ -26,8 +26,8 @@ template inline void GPUReconstructionCPU::runKernelInterface(krnlSetup&& setup, Args const&... args) { HighResTimer* t = nullptr; - GPUDataTypes::RecoStep myStep = S::GetRecoStep() == GPUDataTypes::RecoStep::NoRecoStep ? setup.x.step : S::GetRecoStep(); - if (myStep == GPUDataTypes::RecoStep::NoRecoStep) { + gpudatatypes::RecoStep myStep = S::GetRecoStep() == gpudatatypes::RecoStep::NoRecoStep ? setup.x.step : S::GetRecoStep(); + if (myStep == gpudatatypes::RecoStep::NoRecoStep) { throw std::runtime_error("Failure running general kernel without defining RecoStep"); } int32_t cpuFallback = IsGPU() ? (setup.x.device == krnlDeviceType::CPU ? 2 : (mRecoSteps.stepsGPUMask & myStep) != myStep) : 0; diff --git a/GPU/GPUTracking/Base/GPUReconstructionConvert.cxx b/GPU/GPUTracking/Base/GPUReconstructionConvert.cxx index 6bffdc3560d4a..a4b17b81bf5ac 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionConvert.cxx +++ b/GPU/GPUTracking/Base/GPUReconstructionConvert.cxx @@ -23,7 +23,7 @@ #include "TPCFastTransform.h" #include "GPUTPCClusterData.h" #include "GPUO2DataTypes.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include "GPUTPCGeometry.h" #include "AliHLTTPCRawCluster.h" // VS: It can not be removed. Used in line 93. #include "GPUParam.h" diff --git a/GPU/GPUTracking/Base/GPUReconstructionIncludes.h b/GPU/GPUTracking/Base/GPUReconstructionIncludes.h index d3f11d86a731d..4c057521fe6e7 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionIncludes.h +++ b/GPU/GPUTracking/Base/GPUReconstructionIncludes.h @@ -24,7 +24,7 @@ #include "GPUDef.h" #include "GPULogging.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include #include diff --git a/GPU/GPUTracking/Base/GPUReconstructionLibrary.cxx b/GPU/GPUTracking/Base/GPUReconstructionLibrary.cxx index c70c5d8c51d6f..2e22d4c07e77e 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionLibrary.cxx +++ b/GPU/GPUTracking/Base/GPUReconstructionLibrary.cxx @@ -62,15 +62,15 @@ GPUReconstruction* GPUReconstruction::CreateInstance(const GPUSettingsDeviceBack if (retVal == nullptr) { if (cfg.forceDeviceType) { - GPUError("Error: Could not load GPUReconstruction for specified device: %s (%u)", GPUDataTypes::DEVICE_TYPE_NAMES[type], cfg.deviceType); + GPUError("Error: Could not load GPUReconstruction for specified device: %s (%u)", gpudatatypes::DEVICE_TYPE_NAMES[type], cfg.deviceType); } else if (type != DeviceType::CPU) { - GPUError("Could not load GPUReconstruction for device type %s (%u), falling back to CPU version", GPUDataTypes::DEVICE_TYPE_NAMES[type], cfg.deviceType); + GPUError("Could not load GPUReconstruction for device type %s (%u), falling back to CPU version", gpudatatypes::DEVICE_TYPE_NAMES[type], cfg.deviceType); GPUSettingsDeviceBackend cfg2 = cfg; cfg2.deviceType = DeviceType::CPU; retVal = CreateInstance(cfg2); } } else { - GPUInfo("Created GPUReconstruction instance for device type %s (%u)%s", GPUDataTypes::DEVICE_TYPE_NAMES[type], cfg.deviceType, cfg.master ? " (slave)" : ""); + GPUInfo("Created GPUReconstruction instance for device type %s (%u)%s", gpudatatypes::DEVICE_TYPE_NAMES[type], cfg.deviceType, cfg.master ? " (slave)" : ""); } return retVal; @@ -107,14 +107,14 @@ std::shared_ptr* GPUReconstruction::GetLibrary return nullptr; } if (verbose) { - GPUInfo("%s Support not compiled in for device type %u (%s)", GPUDataTypes::DEVICE_TYPE_NAMES[type], (uint32_t)type, GPUDataTypes::DEVICE_TYPE_NAMES[type]); + GPUInfo("%s Support not compiled in for device type %u (%s)", gpudatatypes::DEVICE_TYPE_NAMES[type], (uint32_t)type, gpudatatypes::DEVICE_TYPE_NAMES[type]); } return nullptr; } GPUReconstruction* GPUReconstruction::CreateInstance(const char* type, bool forceType, GPUReconstruction* master) { - DeviceType t = GPUDataTypes::GetDeviceType(type); + DeviceType t = gpudatatypes::GetDeviceType(type); if (t == DeviceType::INVALID_DEVICE) { GPUError("Invalid device type: %s", type); return nullptr; diff --git a/GPU/GPUTracking/Base/GPUReconstructionProcessing.h b/GPU/GPUTracking/Base/GPUReconstructionProcessing.h index 9e611e57148c6..f582610b57973 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionProcessing.h +++ b/GPU/GPUTracking/Base/GPUReconstructionProcessing.h @@ -92,14 +92,14 @@ class GPUReconstructionProcessing : public GPUReconstruction }; struct krnlExec { - constexpr krnlExec(uint32_t b, uint32_t t, int32_t s, GPUReconstruction::krnlDeviceType d = GPUReconstruction::krnlDeviceType::Auto) : nBlocks(b), nThreads(t), stream(s), device(d), step(GPUDataTypes::RecoStep::NoRecoStep) {} - constexpr krnlExec(uint32_t b, uint32_t t, int32_t s, GPUDataTypes::RecoStep st) : nBlocks(b), nThreads(t), stream(s), device(GPUReconstruction::krnlDeviceType::Auto), step(st) {} - constexpr krnlExec(uint32_t b, uint32_t t, int32_t s, GPUReconstruction::krnlDeviceType d, GPUDataTypes::RecoStep st) : nBlocks(b), nThreads(t), stream(s), device(d), step(st) {} + constexpr krnlExec(uint32_t b, uint32_t t, int32_t s, GPUReconstruction::krnlDeviceType d = GPUReconstruction::krnlDeviceType::Auto) : nBlocks(b), nThreads(t), stream(s), device(d), step(gpudatatypes::RecoStep::NoRecoStep) {} + constexpr krnlExec(uint32_t b, uint32_t t, int32_t s, gpudatatypes::RecoStep st) : nBlocks(b), nThreads(t), stream(s), device(GPUReconstruction::krnlDeviceType::Auto), step(st) {} + constexpr krnlExec(uint32_t b, uint32_t t, int32_t s, GPUReconstruction::krnlDeviceType d, gpudatatypes::RecoStep st) : nBlocks(b), nThreads(t), stream(s), device(d), step(st) {} uint32_t nBlocks; uint32_t nThreads; int32_t stream; GPUReconstruction::krnlDeviceType device; - GPUDataTypes::RecoStep step; + gpudatatypes::RecoStep step; }; struct krnlRunRange { constexpr krnlRunRange() = default; @@ -198,10 +198,10 @@ class GPUReconstructionProcessing : public GPUReconstruction size_t memSize; // Memory size for memory bandwidth computation }; - HighResTimer mTimersGeneralSteps[GPUDataTypes::N_GENERAL_STEPS]; + HighResTimer mTimersGeneralSteps[gpudatatypes::N_GENERAL_STEPS]; std::vector> mTimers; - RecoStepTimerMeta mTimersRecoSteps[GPUDataTypes::N_RECO_STEPS]; + RecoStepTimerMeta mTimersRecoSteps[gpudatatypes::N_RECO_STEPS]; HighResTimer mTimerTotal; template HighResTimer& getKernelTimer(RecoStep step, int32_t num = 0, size_t addMemorySize = 0, bool increment = true); diff --git a/GPU/GPUTracking/Base/GPUReconstructionTimeframe.h b/GPU/GPUTracking/Base/GPUReconstructionTimeframe.h index 47cbfa0a1a5b6..14fc949240a7f 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionTimeframe.h +++ b/GPU/GPUTracking/Base/GPUReconstructionTimeframe.h @@ -16,7 +16,7 @@ #define GPURECONSTRUCTIONTIMEFRAME_H #include "GPUChainTracking.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include "GPUTPCGeometry.h" #include #include diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index 6dd718f07a9f1..6a60eb9edd6d0 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -64,11 +64,11 @@ set(SRCS TRDTracking/GPUTRDTrackerKernels.cxx Base/GPUParam.cxx) -set(SRCS_DATATYPES DataTypes/GPUDataTypes.cxx DataTypes/GPUConfigDump.cxx DataTypes/GPUTPCGMPolynomialField.cxx) +set(SRCS_DATATYPES DataTypes/GPUDataTypesConfig.cxx DataTypes/GPUConfigDump.cxx DataTypes/GPUTPCGMPolynomialField.cxx) set(HDRS_CINT_O2 Merger/GPUTPCGMTrackParam.h Merger/GPUTPCGMMergedTrack.h Merger/GPUTPCGMSectorTrack.h Merger/GPUTPCGMBorderTrack.h TRDTracking/GPUTRDInterfaces.h) set(HDRS_CINT_DATATYPES DataTypes/GPUTPCGMMergedTrackHit.h) -set(HDRS_CINT_O2_ADDITIONAL DataTypes/GPUSettings.h Definitions/GPUSettingsList.h DataTypes/GPUDataTypes.h DataTypes/GPUTRDTrack.h DataTypes/CalibdEdxTrackTopologyPol.h DataTypes/CalibdEdxTrackTopologySpline.h) # Manual dependencies for ROOT dictionary generation +set(HDRS_CINT_O2_ADDITIONAL DataTypes/GPUSettings.h Definitions/GPUSettingsList.h DataTypes/GPUDataTypesIO.h DataTypes/GPUDataTypesConfig.h DataTypes/GPUDataTypesQA.h DataTypes/GPUTRDTrack.h DataTypes/CalibdEdxTrackTopologyPol.h DataTypes/CalibdEdxTrackTopologySpline.h) # Manual dependencies for ROOT dictionary generation set(SRCS_NO_CINT DataTypes/GPUMemorySizeScalers.cxx @@ -107,6 +107,9 @@ set(SRCS_NO_H SectorTracker/GPUTPCTrackerDump.cxx Global/GPUChainTrackingIO.cxx) set(HDRS_INSTALL + ${HDRS_CINT_O2} + ${HDRS_CINT_DATATYPES} + ${HDRS_CINT_O2_ADDITIONAL} Base/GPUConstantMem.h Base/GPUParam.inc Base/GPUParamRTC.h @@ -123,9 +126,7 @@ set(HDRS_INSTALL DataTypes/GPUHostDataTypes.h DataTypes/GPUO2DataTypes.h DataTypes/GPUOutputControl.h - DataTypes/GPUSettings.h DataTypes/GPUTPCGeometry.h - DataTypes/GPUTPCGMMergedTrackHit.h DataTypes/GPUTRDDef.h DataTypes/GPUTRDInterfaceO2Track.h DataTypes/GPUTriggerOutputs.h @@ -139,13 +140,10 @@ set(HDRS_INSTALL Definitions/GPUDef.h Definitions/GPUDefMacros.h Definitions/GPULogging.h - Definitions/GPUSettingsList.h Global/GPUChainTrackingDefs.h Global/GPUChainTrackingDebug.h Global/GPUChainTrackingGetters.inc Global/GPUErrorCodes.h - Merger/GPUTPCGMBorderTrack.h - Merger/GPUTPCGMMergedTrack.h Merger/GPUTPCGMMergerTypes.h qa/GPUQAHelper.h qconfigoptions.h @@ -160,7 +158,6 @@ set(HDRS_INSTALL SectorTracker/GPUTPCTrackLinearisation.h TPCConvert/GPUTPCConvertImpl.h TRDTracking/GPUTRDGeometry.h - TRDTracking/GPUTRDInterfaces.h TRDTracking/GPUTRDSpacePoint.h TRDTracking/GPUTRDTrackData.h TRDTracking/GPUTRDTrackerDebug.h diff --git a/GPU/GPUTracking/DataCompression/GPUTPCCompression.cxx b/GPU/GPUTracking/DataCompression/GPUTPCCompression.cxx index 85cd9598e0bf1..efb7a4af3f323 100644 --- a/GPU/GPUTracking/DataCompression/GPUTPCCompression.cxx +++ b/GPU/GPUTracking/DataCompression/GPUTPCCompression.cxx @@ -38,7 +38,7 @@ void* GPUTPCCompression::SetPointersOutputHost(void* mem) void* GPUTPCCompression::SetPointersScratch(void* mem) { - int32_t gatherMode = mRec->GetProcessingSettings().tpcCompressionGatherMode == -1 ? mRec->getGPUParameters(mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCCompression).par_COMP_GATHER_MODE : mRec->GetProcessingSettings().tpcCompressionGatherMode; + int32_t gatherMode = mRec->GetProcessingSettings().tpcCompressionGatherMode == -1 ? mRec->getGPUParameters(mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCCompression).par_COMP_GATHER_MODE : mRec->GetProcessingSettings().tpcCompressionGatherMode; computePointerWithAlignment(mem, mClusterStatus, mMaxClusters); if (gatherMode >= 2) { computePointerWithAlignment(mem, mAttachedClusterFirstIndex, mMaxTracks); @@ -51,7 +51,7 @@ void* GPUTPCCompression::SetPointersScratch(void* mem) void* GPUTPCCompression::SetPointersOutput(void* mem) { - int32_t gatherMode = mRec->GetProcessingSettings().tpcCompressionGatherMode == -1 ? mRec->getGPUParameters(mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCCompression).par_COMP_GATHER_MODE : mRec->GetProcessingSettings().tpcCompressionGatherMode; + int32_t gatherMode = mRec->GetProcessingSettings().tpcCompressionGatherMode == -1 ? mRec->getGPUParameters(mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCCompression).par_COMP_GATHER_MODE : mRec->GetProcessingSettings().tpcCompressionGatherMode; computePointerWithAlignment(mem, mAttachedClusterFirstIndex, mMaxTrackClusters); if (gatherMode == 1) { SetPointersCompressedClusters(mem, mPtrs, mMaxTrackClusters, mMaxTracks, mMaxClustersInCache, false); @@ -106,7 +106,7 @@ void* GPUTPCCompression::SetPointersMemory(void* mem) void GPUTPCCompression::RegisterMemoryAllocation() { AllocateAndInitializeLate(); - int32_t gatherMode = mRec->GetProcessingSettings().tpcCompressionGatherMode == -1 ? mRec->getGPUParameters(mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCCompression).par_COMP_GATHER_MODE : mRec->GetProcessingSettings().tpcCompressionGatherMode; + int32_t gatherMode = mRec->GetProcessingSettings().tpcCompressionGatherMode == -1 ? mRec->getGPUParameters(mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCCompression).par_COMP_GATHER_MODE : mRec->GetProcessingSettings().tpcCompressionGatherMode; mMemoryResOutputHost = mRec->RegisterMemoryAllocation(this, &GPUTPCCompression::SetPointersOutputHost, GPUMemoryResource::MEMORY_OUTPUT_FLAG | GPUMemoryResource::MEMORY_HOST | GPUMemoryResource::MEMORY_CUSTOM, "TPCCompressionOutputHost"); if (gatherMode == 3) { mMemoryResOutputGPU = mRec->RegisterMemoryAllocation(this, &GPUTPCCompression::SetPointersOutputGPU, GPUMemoryResource::MEMORY_SCRATCH | GPUMemoryResource::MEMORY_GPU | GPUMemoryResource::MEMORY_CUSTOM | GPUMemoryResource::MEMORY_STACK, "TPCCompressionOutputGPU"); diff --git a/GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.h b/GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.h index 81817abf1e6d6..2236f15af9725 100644 --- a/GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.h +++ b/GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.h @@ -27,7 +27,7 @@ namespace o2::gpu class GPUTPCCompressionKernels : public GPUKernelTemplate { public: - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TPCCompression; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::TPCCompression; } enum K : int32_t { step0attached = 0, diff --git a/GPU/GPUTracking/DataCompression/GPUTPCDecompressionKernels.h b/GPU/GPUTracking/DataCompression/GPUTPCDecompressionKernels.h index 1ea93e4acb9d0..2140cfbe5166d 100644 --- a/GPU/GPUTracking/DataCompression/GPUTPCDecompressionKernels.h +++ b/GPU/GPUTracking/DataCompression/GPUTPCDecompressionKernels.h @@ -27,7 +27,7 @@ namespace o2::gpu class GPUTPCDecompressionKernels : public GPUKernelTemplate { public: - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TPCDecompression; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::TPCDecompression; } enum K : int32_t { step0attached = 0, diff --git a/GPU/GPUTracking/DataTypes/GPUConfigDump.cxx b/GPU/GPUTracking/DataTypes/GPUConfigDump.cxx index 7ec2df3a2f186..56543d5f2e43d 100644 --- a/GPU/GPUTracking/DataTypes/GPUConfigDump.cxx +++ b/GPU/GPUTracking/DataTypes/GPUConfigDump.cxx @@ -13,7 +13,7 @@ /// \author David Rohr #include "GPUConfigDump.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include "GPUSettings.h" #include diff --git a/GPU/GPUTracking/DataTypes/GPUDataTypes.cxx b/GPU/GPUTracking/DataTypes/GPUDataTypesConfig.cxx similarity index 73% rename from GPU/GPUTracking/DataTypes/GPUDataTypes.cxx rename to GPU/GPUTracking/DataTypes/GPUDataTypesConfig.cxx index c544ac610cdfa..80ca919dd29e1 100644 --- a/GPU/GPUTracking/DataTypes/GPUDataTypes.cxx +++ b/GPU/GPUTracking/DataTypes/GPUDataTypesConfig.cxx @@ -9,19 +9,15 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file GPUDataTypes.cxx +/// \file GPUDataTypesConfig.cxx /// \author David Rohr -#include "GPUDataTypes.h" +#include "GPUDataTypesConfig.h" #include using namespace o2::gpu; -constexpr const char* const GPUDataTypes::DEVICE_TYPE_NAMES[]; -constexpr const char* const GPUDataTypes::RECO_STEP_NAMES[]; -constexpr const char* const GPUDataTypes::GENERAL_STEP_NAMES[]; - -GPUDataTypes::DeviceType GPUDataTypes::GetDeviceType(const char* type) +gpudatatypes::DeviceType gpudatatypes::GetDeviceType(const char* type) { for (uint32_t i = 1; i < sizeof(DEVICE_TYPE_NAMES) / sizeof(DEVICE_TYPE_NAMES[0]); i++) { if (strcmp(DEVICE_TYPE_NAMES[i], type) == 0) { diff --git a/GPU/GPUTracking/DataTypes/GPUDataTypesConfig.h b/GPU/GPUTracking/DataTypes/GPUDataTypesConfig.h new file mode 100644 index 0000000000000..6535bb93770c4 --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUDataTypesConfig.h @@ -0,0 +1,80 @@ +// 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 GPUDataTypesConfig.h +/// \author David Rohr + +#ifndef GPUDATATYPESCONFIG_H +#define GPUDATATYPESCONFIG_H + +#include "GPUCommonDef.h" + +// These are basic and non-complex data types, which will also be visible on the GPU. +// Please add complex data types required on the host but not GPU to GPUHostDataTypes.h and forward-declare! +#ifndef GPUCA_GPUCODE_DEVICE +#include // for bitfield below +#include +#endif + +namespace o2::gpu +{ +#include "utils/bitfield.h" + +namespace gpudatatypes +{ +// clang-format off +enum class GeometryType : uint32_t { RESERVED_GEOMETRY = 0, ALIROOT = 1, O2 = 2 }; +enum DeviceType : uint32_t { INVALID_DEVICE = 0, CPU = 1, CUDA = 2, HIP = 3, OCL = 4 }; +enum class GeneralStep : uint32_t { Prepare = 1, QA = 2 }; +// clang-format on + +enum class RecoStep : uint32_t { TPCConversion = 1, + TPCSectorTracking = 2, + TPCMerging = 4, + TPCCompression = 8, + TRDTracking = 16, + ITSTracking = 32, + TPCdEdx = 64, + TPCClusterFinding = 128, + TPCDecompression = 256, + Refit = 512, + AllRecoSteps = 0x7FFFFFFF, + NoRecoStep = 0 }; +enum class InOutType : uint32_t { TPCClusters = 1, + OBSOLETE = 2, + TPCMergedTracks = 4, + TPCCompressedClusters = 8, + TRDTracklets = 16, + TRDTracks = 32, + TPCRaw = 64, + ITSClusters = 128, + ITSTracks = 256 }; +#ifndef __OPENCL__ +static constexpr const char* const DEVICE_TYPE_NAMES[] = {"INVALID", "CPU", "CUDA", "HIP", "OCL"}; +static constexpr const char* const RECO_STEP_NAMES[] = {"TPC Transformation", "TPC Sector Tracking", "TPC Track Merging and Fit", "TPC Compression", "TRD Tracking", "ITS Tracking", "TPC dEdx Computation", "TPC Cluster Finding", "TPC Decompression", "Global Refit"}; +static constexpr const char* const GENERAL_STEP_NAMES[] = {"Prepare", "QA"}; +constexpr static int32_t N_RECO_STEPS = sizeof(gpudatatypes::RECO_STEP_NAMES) / sizeof(gpudatatypes::RECO_STEP_NAMES[0]); +constexpr static int32_t N_GENERAL_STEPS = sizeof(gpudatatypes::GENERAL_STEP_NAMES) / sizeof(gpudatatypes::GENERAL_STEP_NAMES[0]); +#endif +typedef bitfield RecoStepField; +typedef bitfield InOutTypeField; +DeviceType GetDeviceType(const char* type); +} // namespace gpudatatypes + +struct GPURecoStepConfiguration { + gpudatatypes::RecoStepField steps = 0; + gpudatatypes::RecoStepField stepsGPUMask = gpudatatypes::RecoStep::AllRecoSteps; + gpudatatypes::InOutTypeField inputs = 0; + gpudatatypes::InOutTypeField outputs = 0; +}; +} // namespace o2::gpu + +#endif diff --git a/GPU/GPUTracking/DataTypes/GPUDataTypes.h b/GPU/GPUTracking/DataTypes/GPUDataTypesIO.h similarity index 74% rename from GPU/GPUTracking/DataTypes/GPUDataTypes.h rename to GPU/GPUTracking/DataTypes/GPUDataTypesIO.h index 8bf8084e048fd..fd98cba1dadaa 100644 --- a/GPU/GPUTracking/DataTypes/GPUDataTypes.h +++ b/GPU/GPUTracking/DataTypes/GPUDataTypesIO.h @@ -9,18 +9,17 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file GPUDataTypes.h +/// \file GPUDataTypesIO.h /// \author David Rohr -#ifndef GPUDATATYPES_H -#define GPUDATATYPES_H +#ifndef GPUDATATYPESIO_H +#define GPUDATATYPESIO_H #include "GPUCommonDef.h" // These are basic and non-complex data types, which will also be visible on the GPU. // Please add complex data types required on the host but not GPU to GPUHostDataTypes.h and forward-declare! #ifndef GPUCA_GPUCODE_DEVICE -#include // for bitfield below #include #endif #include "GPUTRDDef.h" @@ -96,8 +95,6 @@ class TPCFastTransform; struct TPCPadGainCalib; struct TPCZSLinkMapping; -#include "utils/bitfield.h" - class GPUTPCTrack; class GPUTPCHitId; class GPUTPCGMMergedTrack; @@ -111,55 +108,10 @@ struct GPUTRDTrackletLabels; struct GPUTPCDigitsMCInput; struct GPUSettingsTF; -class GPUDataTypes +namespace gpudatatypes { - public: - // clang-format off - enum class GeometryType : uint32_t { RESERVED_GEOMETRY = 0, ALIROOT = 1, O2 = 2 }; - enum DeviceType : uint32_t { INVALID_DEVICE = 0, CPU = 1, CUDA = 2, HIP = 3, OCL = 4 }; - enum class GeneralStep { Prepare = 1, QA = 2 }; - // clang-format on - - enum class RecoStep { TPCConversion = 1, - TPCSectorTracking = 2, - TPCMerging = 4, - TPCCompression = 8, - TRDTracking = 16, - ITSTracking = 32, - TPCdEdx = 64, - TPCClusterFinding = 128, - TPCDecompression = 256, - Refit = 512, - AllRecoSteps = 0x7FFFFFFF, - NoRecoStep = 0 }; - enum class InOutType { TPCClusters = 1, - OBSOLETE = 2, - TPCMergedTracks = 4, - TPCCompressedClusters = 8, - TRDTracklets = 16, - TRDTracks = 32, - TPCRaw = 64, - ITSClusters = 128, - ITSTracks = 256 }; -#ifndef __OPENCL__ - static constexpr const char* const DEVICE_TYPE_NAMES[] = {"INVALID", "CPU", "CUDA", "HIP", "OCL"}; - static constexpr const char* const RECO_STEP_NAMES[] = {"TPC Transformation", "TPC Sector Tracking", "TPC Track Merging and Fit", "TPC Compression", "TRD Tracking", "ITS Tracking", "TPC dEdx Computation", "TPC Cluster Finding", "TPC Decompression", "Global Refit"}; - static constexpr const char* const GENERAL_STEP_NAMES[] = {"Prepare", "QA"}; - constexpr static int32_t N_RECO_STEPS = sizeof(GPUDataTypes::RECO_STEP_NAMES) / sizeof(GPUDataTypes::RECO_STEP_NAMES[0]); - constexpr static int32_t N_GENERAL_STEPS = sizeof(GPUDataTypes::GENERAL_STEP_NAMES) / sizeof(GPUDataTypes::GENERAL_STEP_NAMES[0]); -#endif - typedef bitfield RecoStepField; - typedef bitfield InOutTypeField; - static constexpr uint32_t NSECTORS = 36; - static DeviceType GetDeviceType(const char* type); -}; - -struct GPURecoStepConfiguration { - GPUDataTypes::RecoStepField steps = 0; - GPUDataTypes::RecoStepField stepsGPUMask = GPUDataTypes::RecoStep::AllRecoSteps; - GPUDataTypes::InOutTypeField inputs = 0; - GPUDataTypes::InOutTypeField outputs = 0; -}; +static constexpr uint32_t NSECTORS = 36; +} // namespace gpudatatypes template struct DefaultPtr { @@ -191,7 +143,7 @@ typedef GPUCalibObjectsTemplate GPUCalibObjects; // NOTE: These 2 mu typedef GPUCalibObjectsTemplate GPUCalibObjectsConst; struct GPUTrackingInOutZS { - static constexpr uint32_t NSECTORS = GPUDataTypes::NSECTORS; + static constexpr uint32_t NSECTORS = gpudatatypes::NSECTORS; static constexpr uint32_t NENDPOINTS = 20; struct GPUTrackingInOutZSSector { const void* const* zsPtr[NENDPOINTS]; @@ -209,7 +161,7 @@ struct GPUTrackingInOutZS { }; struct GPUTrackingInOutDigits { - static constexpr uint32_t NSECTORS = GPUDataTypes::NSECTORS; + static constexpr uint32_t NSECTORS = gpudatatypes::NSECTORS; const o2::tpc::Digit* tpcDigits[NSECTORS] = {nullptr}; size_t nTPCDigits[NSECTORS] = {0}; const GPUTPCDigitsMCInput* tpcDigitsMC = nullptr; @@ -219,7 +171,7 @@ struct GPUTrackingInOutPointers { GPUTrackingInOutPointers() = default; // TPC - static constexpr uint32_t NSECTORS = GPUDataTypes::NSECTORS; + static constexpr uint32_t NSECTORS = gpudatatypes::NSECTORS; const GPUTrackingInOutZS* tpcZS = nullptr; const GPUTrackingInOutDigits* tpcPackedDigits = nullptr; const GPUTPCClusterData* clusterData[NSECTORS] = {nullptr}; diff --git a/GPU/GPUTracking/DataTypes/GPUDataTypesQA.h b/GPU/GPUTracking/DataTypes/GPUDataTypesQA.h new file mode 100644 index 0000000000000..6ec6de0ed4a57 --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUDataTypesQA.h @@ -0,0 +1,42 @@ +// 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 GPUDataTypesIO.h +/// \author David Rohr + +#ifndef GPUDATATYPESQA_H +#define GPUDATATYPESQA_H + +#include "GPUCommonDef.h" + +#include + +namespace o2::gpu::gpudatatypes::gpuqa +{ +enum gpuQATaskIds : int32_t { + tasksNone = 0, + taskTrackingEff = 1, + taskTrackingRes = 2, + taskTrackingResPull = 4, + taskClusterAttach = 8, + tasksAllMC = 16 - 1, + taskTrackStatistics = 16, + taskClusterCounts = 32, + taskClusterRejection = 64, + tasksAll = 128 - 1, + tasksDefault = tasksAll, + tasksDefaultPostprocess = tasksDefault & ~taskClusterCounts, + tasksAllNoQC = tasksAll & ~tasksAllMC, + tasksAutomatic = -1 +}; +} // namespace o2::gpu::gpudatatypes::gpuqa + +#endif diff --git a/GPU/GPUTracking/DataTypes/GPUO2ConfigurableParam.cxx b/GPU/GPUTracking/DataTypes/GPUO2ConfigurableParam.cxx index f5b3ea8b285f5..60fdbe8042c2d 100644 --- a/GPU/GPUTracking/DataTypes/GPUO2ConfigurableParam.cxx +++ b/GPU/GPUTracking/DataTypes/GPUO2ConfigurableParam.cxx @@ -14,7 +14,7 @@ #include "GPUO2ConfigurableParam.h" #include "Interface/GPUO2InterfaceConfiguration.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include "GPUConfigDump.h" using namespace o2::gpu; @@ -122,7 +122,7 @@ GPUSettingsO2 GPUO2InterfaceConfiguration::ReadConfigurableParam(GPUO2InterfaceC if (obj.configReconstruction.tpc.trackReferenceX == 1000.f) { obj.configReconstruction.tpc.trackReferenceX = 83.f; } - obj.configDeviceBackend.deviceType = GPUDataTypes::GetDeviceType(global.deviceType.c_str()); + obj.configDeviceBackend.deviceType = gpudatatypes::GetDeviceType(global.deviceType.c_str()); obj.configDeviceBackend.forceDeviceType = global.forceDeviceType; return global; } diff --git a/GPU/GPUTracking/DataTypes/GPUSettings.h b/GPU/GPUTracking/DataTypes/GPUSettings.h index 9e3a3e9bd6ce8..34b378b046aec 100644 --- a/GPU/GPUTracking/DataTypes/GPUSettings.h +++ b/GPU/GPUTracking/DataTypes/GPUSettings.h @@ -16,7 +16,7 @@ #define GPUSETTINGS_H #include "GPUCommonDef.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesConfig.h" #include "GPUTPCGMMergedTrackHit.h" #ifndef GPUCA_GPUCODE_DEVICE #include @@ -73,7 +73,7 @@ struct GPUSettingsTF { // Settings defining the setup of the GPUReconstruction processing (basically selecting the device / class instance) struct GPUSettingsDeviceBackend { - uint32_t deviceType = GPUDataTypes::DeviceType::CPU; // Device type, shall use GPUDataTypes::DEVICE_TYPE constants, e.g. CPU / CUDA + uint32_t deviceType = gpudatatypes::DeviceType::CPU; // Device type, shall use gpudatatypes::DEVICE_TYPE constants, e.g. CPU / CUDA uint8_t forceDeviceType = 1; // Fail if device initialization fails, otherwise falls back to CPU GPUReconstruction* master = nullptr; // GPUReconstruction master object }; diff --git a/GPU/GPUTracking/Global/GPUChain.cxx b/GPU/GPUTracking/Global/GPUChain.cxx index 300de31a509ba..fe0cf59c6c28e 100644 --- a/GPU/GPUTracking/Global/GPUChain.cxx +++ b/GPU/GPUTracking/Global/GPUChain.cxx @@ -18,33 +18,33 @@ using namespace o2::gpu; constexpr GPUChain::krnlRunRange GPUChain::krnlRunRangeNone; constexpr GPUChain::krnlEvent GPUChain::krnlEventNone; -GPUChain::krnlExec GPUChain::GetGrid(uint32_t totalItems, uint32_t nThreads, int32_t stream, GPUReconstruction::krnlDeviceType d, GPUDataTypes::RecoStep st) +GPUChain::krnlExec GPUChain::GetGrid(uint32_t totalItems, uint32_t nThreads, int32_t stream, GPUReconstruction::krnlDeviceType d, gpudatatypes::RecoStep st) { const uint32_t nBlocks = (totalItems + nThreads - 1) / nThreads; return {nBlocks, nThreads, stream, d, st}; } -GPUChain::krnlExec GPUChain::GetGrid(uint32_t totalItems, int32_t stream, GPUReconstruction::krnlDeviceType d, GPUDataTypes::RecoStep st) +GPUChain::krnlExec GPUChain::GetGrid(uint32_t totalItems, int32_t stream, GPUReconstruction::krnlDeviceType d, gpudatatypes::RecoStep st) { return {(uint32_t)-1, totalItems, stream, d, st}; } -GPUChain::krnlExec GPUChain::GetGridBlk(uint32_t nBlocks, int32_t stream, GPUReconstruction::krnlDeviceType d, GPUDataTypes::RecoStep st) +GPUChain::krnlExec GPUChain::GetGridBlk(uint32_t nBlocks, int32_t stream, GPUReconstruction::krnlDeviceType d, gpudatatypes::RecoStep st) { return {(uint32_t)-2, nBlocks, stream, d, st}; } -GPUChain::krnlExec GPUChain::GetGridBlkStep(uint32_t nBlocks, int32_t stream, GPUDataTypes::RecoStep st) +GPUChain::krnlExec GPUChain::GetGridBlkStep(uint32_t nBlocks, int32_t stream, gpudatatypes::RecoStep st) { return {(uint32_t)-2, nBlocks, stream, GPUReconstruction::krnlDeviceType::Auto, st}; } -GPUChain::krnlExec GPUChain::GetGridAuto(int32_t stream, GPUReconstruction::krnlDeviceType d, GPUDataTypes::RecoStep st) +GPUChain::krnlExec GPUChain::GetGridAuto(int32_t stream, GPUReconstruction::krnlDeviceType d, gpudatatypes::RecoStep st) { return {(uint32_t)-3, 0, stream, d, st}; } -GPUChain::krnlExec GPUChain::GetGridAutoStep(int32_t stream, GPUDataTypes::RecoStep st) +GPUChain::krnlExec GPUChain::GetGridAutoStep(int32_t stream, gpudatatypes::RecoStep st) { return {(uint32_t)-3, 0, stream, GPUReconstruction::krnlDeviceType::Auto, st}; } diff --git a/GPU/GPUTracking/Global/GPUChain.h b/GPU/GPUTracking/Global/GPUChain.h index 6831fbd15080a..907ed7ea97c12 100644 --- a/GPU/GPUTracking/Global/GPUChain.h +++ b/GPU/GPUTracking/Global/GPUChain.h @@ -200,15 +200,15 @@ class GPUChain return mRec->getTimer(name, num); } // Get GRID with NBLOCKS minimal such that nThreads * NBLOCS >= totalItems - krnlExec GetGrid(uint32_t totalItems, uint32_t nThreads, int32_t stream, GPUReconstruction::krnlDeviceType d = GPUReconstruction::krnlDeviceType::Auto, GPUDataTypes::RecoStep st = GPUDataTypes::RecoStep::NoRecoStep); + krnlExec GetGrid(uint32_t totalItems, uint32_t nThreads, int32_t stream, GPUReconstruction::krnlDeviceType d = GPUReconstruction::krnlDeviceType::Auto, gpudatatypes::RecoStep st = gpudatatypes::RecoStep::NoRecoStep); // Get GRID with NBLOCKS minimal such that ideal number of threads * NBLOCKS >= totalItems - krnlExec GetGrid(uint32_t totalItems, int32_t stream, GPUReconstruction::krnlDeviceType d = GPUReconstruction::krnlDeviceType::Auto, GPUDataTypes::RecoStep st = GPUDataTypes::RecoStep::NoRecoStep); + krnlExec GetGrid(uint32_t totalItems, int32_t stream, GPUReconstruction::krnlDeviceType d = GPUReconstruction::krnlDeviceType::Auto, gpudatatypes::RecoStep st = gpudatatypes::RecoStep::NoRecoStep); // Get GRID with specified number of blocks, each block with ideal number of threads - krnlExec GetGridBlk(uint32_t nBlocks, int32_t stream, GPUReconstruction::krnlDeviceType d = GPUReconstruction::krnlDeviceType::Auto, GPUDataTypes::RecoStep st = GPUDataTypes::RecoStep::NoRecoStep); - krnlExec GetGridBlkStep(uint32_t nBlocks, int32_t stream, GPUDataTypes::RecoStep st = GPUDataTypes::RecoStep::NoRecoStep); + krnlExec GetGridBlk(uint32_t nBlocks, int32_t stream, GPUReconstruction::krnlDeviceType d = GPUReconstruction::krnlDeviceType::Auto, gpudatatypes::RecoStep st = gpudatatypes::RecoStep::NoRecoStep); + krnlExec GetGridBlkStep(uint32_t nBlocks, int32_t stream, gpudatatypes::RecoStep st = gpudatatypes::RecoStep::NoRecoStep); // Get GRID with ideal number of threads / blocks for GPU - krnlExec GetGridAuto(int32_t stream, GPUReconstruction::krnlDeviceType d = GPUReconstruction::krnlDeviceType::Auto, GPUDataTypes::RecoStep st = GPUDataTypes::RecoStep::NoRecoStep); - krnlExec GetGridAutoStep(int32_t stream, GPUDataTypes::RecoStep st = GPUDataTypes::RecoStep::NoRecoStep); + krnlExec GetGridAuto(int32_t stream, GPUReconstruction::krnlDeviceType d = GPUReconstruction::krnlDeviceType::Auto, gpudatatypes::RecoStep st = gpudatatypes::RecoStep::NoRecoStep); + krnlExec GetGridAutoStep(int32_t stream, gpudatatypes::RecoStep st = gpudatatypes::RecoStep::NoRecoStep); inline uint32_t BlockCount() const { return mRec->mMultiprocessorCount; } inline uint32_t WarpSize() const { return mRec->mWarpSize; } diff --git a/GPU/GPUTracking/Global/GPUChainITS.cxx b/GPU/GPUTracking/Global/GPUChainITS.cxx index c72023bdf42ce..598f7a61cac1a 100644 --- a/GPU/GPUTracking/Global/GPUChainITS.cxx +++ b/GPU/GPUTracking/Global/GPUChainITS.cxx @@ -36,7 +36,7 @@ class GPUFrameworkExternalAllocator final : public o2::its::ExternalAllocator } void popTagOffStack(uint64_t tag) final { - mFWReco->PopNonPersistentMemory(GPUDataTypes::RecoStep::ITSTracking, tag); + mFWReco->PopNonPersistentMemory(gpudatatypes::RecoStep::ITSTracking, tag); } void setReconstructionFramework(o2::gpu::GPUReconstruction* fwr) { mFWReco = fwr; } diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index 8a0d45a33ca93..f370b756e2cdb 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -168,78 +168,78 @@ void GPUChainTracking::MemorySize(size_t& gpuMem, size_t& pageLockedHostMem) bool GPUChainTracking::ValidateSteps() { - if ((GetRecoSteps() & GPUDataTypes::RecoStep::TPCdEdx) && !(GetRecoSteps() & GPUDataTypes::RecoStep::TPCMerging)) { + if ((GetRecoSteps() & gpudatatypes::RecoStep::TPCdEdx) && !(GetRecoSteps() & gpudatatypes::RecoStep::TPCMerging)) { GPUError("Invalid Reconstruction Step Setting: dEdx requires TPC Merger to be active"); return false; } - if ((GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCdEdx) && !(GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCMerging)) { + if ((GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCdEdx) && !(GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCMerging)) { GPUError("Invalid GPU Reconstruction Step Setting: dEdx requires TPC Merger to be active"); return false; } - if (((GetRecoSteps() & GPUDataTypes::RecoStep::TPCSectorTracking) || (GetRecoSteps() & GPUDataTypes::RecoStep::TPCMerging)) && !(GetRecoSteps() & GPUDataTypes::RecoStep::TPCConversion)) { + if (((GetRecoSteps() & gpudatatypes::RecoStep::TPCSectorTracking) || (GetRecoSteps() & gpudatatypes::RecoStep::TPCMerging)) && !(GetRecoSteps() & gpudatatypes::RecoStep::TPCConversion)) { GPUError("Invalid Reconstruction Step Setting: Tracking requires TPC Conversion to be active"); return false; } - if ((GetRecoSteps() & GPUDataTypes::RecoStep::TPCClusterFinding) && !(GetRecoStepsInputs() & GPUDataTypes::InOutType::TPCRaw)) { + if ((GetRecoSteps() & gpudatatypes::RecoStep::TPCClusterFinding) && !(GetRecoStepsInputs() & gpudatatypes::InOutType::TPCRaw)) { GPUError("Invalid input, TPC Clusterizer needs TPC raw input"); return false; } - if ((GetRecoSteps() & GPUDataTypes::RecoStep::TPCMerging) && !(GetRecoSteps() & GPUDataTypes::RecoStep::TPCConversion)) { + if ((GetRecoSteps() & gpudatatypes::RecoStep::TPCMerging) && !(GetRecoSteps() & gpudatatypes::RecoStep::TPCConversion)) { GPUError("Invalid input / output / step, merger cannot read/store sectors tracks and needs TPC conversion"); return false; } - bool tpcClustersAvail = (GetRecoStepsInputs() & GPUDataTypes::InOutType::TPCClusters) || (GetRecoSteps() & GPUDataTypes::RecoStep::TPCClusterFinding) || (GetRecoSteps() & GPUDataTypes::RecoStep::TPCDecompression); - if ((GetRecoSteps() & GPUDataTypes::RecoStep::TPCMerging) && !tpcClustersAvail) { + bool tpcClustersAvail = (GetRecoStepsInputs() & gpudatatypes::InOutType::TPCClusters) || (GetRecoSteps() & gpudatatypes::RecoStep::TPCClusterFinding) || (GetRecoSteps() & gpudatatypes::RecoStep::TPCDecompression); + if ((GetRecoSteps() & gpudatatypes::RecoStep::TPCMerging) && !tpcClustersAvail) { GPUError("Invalid Inputs for track merging, TPC Clusters required"); return false; } #ifndef GPUCA_TPC_GEOMETRY_O2 - if (GetRecoSteps() & GPUDataTypes::RecoStep::TPCClusterFinding) { + if (GetRecoSteps() & gpudatatypes::RecoStep::TPCClusterFinding) { GPUError("Can not run TPC GPU Cluster Finding with Run 2 Data"); return false; } #endif - if (((GetRecoSteps() & GPUDataTypes::RecoStep::TPCConversion) || (GetRecoSteps() & GPUDataTypes::RecoStep::TPCSectorTracking) || (GetRecoSteps() & GPUDataTypes::RecoStep::TPCCompression) || (GetRecoSteps() & GPUDataTypes::RecoStep::TPCdEdx)) && !tpcClustersAvail) { + if (((GetRecoSteps() & gpudatatypes::RecoStep::TPCConversion) || (GetRecoSteps() & gpudatatypes::RecoStep::TPCSectorTracking) || (GetRecoSteps() & gpudatatypes::RecoStep::TPCCompression) || (GetRecoSteps() & gpudatatypes::RecoStep::TPCdEdx)) && !tpcClustersAvail) { GPUError("Missing input for TPC Cluster conversion / sector tracking / compression / dEdx: TPC Clusters required"); return false; } - if ((GetRecoSteps() & GPUDataTypes::RecoStep::TPCMerging) && !(GetRecoSteps() & GPUDataTypes::RecoStep::TPCSectorTracking)) { + if ((GetRecoSteps() & gpudatatypes::RecoStep::TPCMerging) && !(GetRecoSteps() & gpudatatypes::RecoStep::TPCSectorTracking)) { GPUError("Input for TPC merger missing"); return false; } - if ((GetRecoSteps() & GPUDataTypes::RecoStep::TPCCompression) && !((GetRecoStepsInputs() & GPUDataTypes::InOutType::TPCMergedTracks) || (GetRecoSteps() & GPUDataTypes::RecoStep::TPCMerging))) { + if ((GetRecoSteps() & gpudatatypes::RecoStep::TPCCompression) && !((GetRecoStepsInputs() & gpudatatypes::InOutType::TPCMergedTracks) || (GetRecoSteps() & gpudatatypes::RecoStep::TPCMerging))) { GPUError("Input for TPC compressor missing"); return false; } - if ((GetRecoSteps() & GPUDataTypes::RecoStep::TRDTracking) && (!((GetRecoStepsInputs() & GPUDataTypes::InOutType::TPCMergedTracks) || (GetRecoSteps() & GPUDataTypes::RecoStep::TPCMerging)) || !(GetRecoStepsInputs() & GPUDataTypes::InOutType::TRDTracklets))) { + if ((GetRecoSteps() & gpudatatypes::RecoStep::TRDTracking) && (!((GetRecoStepsInputs() & gpudatatypes::InOutType::TPCMergedTracks) || (GetRecoSteps() & gpudatatypes::RecoStep::TPCMerging)) || !(GetRecoStepsInputs() & gpudatatypes::InOutType::TRDTracklets))) { GPUError("Input for TRD Tracker missing"); return false; } - if ((GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCRaw) || (GetRecoStepsOutputs() & GPUDataTypes::InOutType::TRDTracklets)) { + if ((GetRecoStepsOutputs() & gpudatatypes::InOutType::TPCRaw) || (GetRecoStepsOutputs() & gpudatatypes::InOutType::TRDTracklets)) { GPUError("TPC Raw / TPC Clusters / TRD Tracklets cannot be output"); return false; } - if ((GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCMergedTracks) && !(GetRecoSteps() & GPUDataTypes::RecoStep::TPCMerging)) { + if ((GetRecoStepsOutputs() & gpudatatypes::InOutType::TPCMergedTracks) && !(GetRecoSteps() & gpudatatypes::RecoStep::TPCMerging)) { GPUError("No TPC Merged Track Output available"); return false; } - if ((GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCCompressedClusters) && !(GetRecoSteps() & GPUDataTypes::RecoStep::TPCCompression)) { + if ((GetRecoStepsOutputs() & gpudatatypes::InOutType::TPCCompressedClusters) && !(GetRecoSteps() & gpudatatypes::RecoStep::TPCCompression)) { GPUError("No TPC Compression Output available"); return false; } - if ((GetRecoStepsOutputs() & GPUDataTypes::InOutType::TRDTracks) && !(GetRecoSteps() & GPUDataTypes::RecoStep::TRDTracking)) { + if ((GetRecoStepsOutputs() & gpudatatypes::InOutType::TRDTracks) && !(GetRecoSteps() & gpudatatypes::RecoStep::TRDTracking)) { GPUError("No TRD Tracker Output available"); return false; } - if ((GetRecoSteps() & GPUDataTypes::RecoStep::TPCdEdx) && (processors()->calibObjects.dEdxCalibContainer == nullptr)) { + if ((GetRecoSteps() & gpudatatypes::RecoStep::TPCdEdx) && (processors()->calibObjects.dEdxCalibContainer == nullptr)) { GPUError("Cannot run dE/dx without dE/dx calibration container object"); return false; } - if ((GetRecoSteps() & GPUDataTypes::RecoStep::TPCClusterFinding) && processors()->calibObjects.tpcPadGain == nullptr) { + if ((GetRecoSteps() & gpudatatypes::RecoStep::TPCClusterFinding) && processors()->calibObjects.tpcPadGain == nullptr) { GPUError("Cannot run gain calibration without calibration object"); return false; } - if ((GetRecoSteps() & GPUDataTypes::RecoStep::TPCClusterFinding) && processors()->calibObjects.tpcZSLinkMapping == nullptr && mIOPtrs.tpcZS != nullptr) { + if ((GetRecoSteps() & gpudatatypes::RecoStep::TPCClusterFinding) && processors()->calibObjects.tpcZSLinkMapping == nullptr && mIOPtrs.tpcZS != nullptr) { GPUError("Cannot run TPC ZS Decoder without mapping object. (tpczslinkmapping.dump missing?)"); return false; } @@ -248,7 +248,7 @@ bool GPUChainTracking::ValidateSteps() bool GPUChainTracking::ValidateSettings() { - int32_t gatherMode = mRec->GetProcessingSettings().tpcCompressionGatherMode == -1 ? mRec->getGPUParameters(mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCCompression).par_COMP_GATHER_MODE : mRec->GetProcessingSettings().tpcCompressionGatherMode; + int32_t gatherMode = mRec->GetProcessingSettings().tpcCompressionGatherMode == -1 ? mRec->getGPUParameters(mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCCompression).par_COMP_GATHER_MODE : mRec->GetProcessingSettings().tpcCompressionGatherMode; if ((param().rec.tpc.nWays & 1) == 0) { GPUError("nWay setting musst be odd number!"); return false; @@ -265,7 +265,7 @@ bool GPUChainTracking::ValidateSettings() GPUError("NStreams of %d insufficient for %d nTPCClustererLanes", mRec->NStreams(), (int32_t)GetProcessingSettings().nTPCClustererLanes); return false; } - if ((mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCCompression) && GetProcessingSettings().noGPUMemoryRegistration && gatherMode != 3) { + if ((mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCCompression) && GetProcessingSettings().noGPUMemoryRegistration && gatherMode != 3) { GPUError("noGPUMemoryRegistration only possible with gather mode 3 (set to %d / %d)", mRec->GetProcessingSettings().tpcCompressionGatherMode, gatherMode); return false; } @@ -273,7 +273,7 @@ bool GPUChainTracking::ValidateSettings() GPUError("Clusterizer and merger Sanity checks only supported when not running on GPU"); return false; } - if (GetProcessingSettings().tpcWriteClustersAfterRejection && (mRec->IsGPU() || param().rec.tpc.compressionTypeMask || !(GetRecoSteps() & GPUDataTypes::RecoStep::TPCCompression))) { + if (GetProcessingSettings().tpcWriteClustersAfterRejection && (mRec->IsGPU() || param().rec.tpc.compressionTypeMask || !(GetRecoSteps() & gpudatatypes::RecoStep::TPCCompression))) { GPUError("tpcWriteClustersAfterRejection requires compressionTypeMask = 0, no GPU usage, and compression enabled"); return false; } @@ -282,13 +282,13 @@ bool GPUChainTracking::ValidateSettings() GPUError("Cannot use double pipeline with tpcFreeAllocatedMemoryAfterProcessing"); return false; } - if (!GetRecoStepsOutputs().isOnlySet(GPUDataTypes::InOutType::TPCMergedTracks, GPUDataTypes::InOutType::TPCCompressedClusters, GPUDataTypes::InOutType::TPCClusters)) { + if (!GetRecoStepsOutputs().isOnlySet(gpudatatypes::InOutType::TPCMergedTracks, gpudatatypes::InOutType::TPCCompressedClusters, gpudatatypes::InOutType::TPCClusters)) { GPUError("Invalid outputs for double pipeline mode 0x%x", (uint32_t)GetRecoStepsOutputs()); return false; } - if (((GetRecoStepsOutputs().isSet(GPUDataTypes::InOutType::TPCCompressedClusters) && mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::compressedClusters)] == nullptr) || - (GetRecoStepsOutputs().isSet(GPUDataTypes::InOutType::TPCClusters) && mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clustersNative)] == nullptr) || - (GetRecoStepsOutputs().isSet(GPUDataTypes::InOutType::TPCMergedTracks) && mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTracks)] == nullptr) || + if (((GetRecoStepsOutputs().isSet(gpudatatypes::InOutType::TPCCompressedClusters) && mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::compressedClusters)] == nullptr) || + (GetRecoStepsOutputs().isSet(gpudatatypes::InOutType::TPCClusters) && mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clustersNative)] == nullptr) || + (GetRecoStepsOutputs().isSet(gpudatatypes::InOutType::TPCMergedTracks) && mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTracks)] == nullptr) || (GetProcessingSettings().outputSharedClusterMap && mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::sharedClusterMap)] == nullptr))) { GPUError("Must use external output for double pipeline mode"); return false; @@ -297,16 +297,16 @@ bool GPUChainTracking::ValidateSettings() GPUError("Double pipeline incompatible to compression mode 1"); return false; } - if (!(GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCCompression) || !(GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding) || param().rec.fwdTPCDigitsAsClusters) { + if (!(GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCCompression) || !(GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCClusterFinding) || param().rec.fwdTPCDigitsAsClusters) { GPUError("Invalid reconstruction settings for double pipeline: Needs compression and cluster finding"); return false; } } - if ((GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCCompression) && !(GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCCompression) && (gatherMode == 1 || gatherMode == 3)) { + if ((GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCCompression) && !(GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCCompression) && (gatherMode == 1 || gatherMode == 3)) { GPUError("Invalid tpcCompressionGatherMode for compression on CPU"); return false; } - if (GetProcessingSettings().tpcApplyClusterFilterOnCPU > 0 && (GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding || GetProcessingSettings().runMC)) { + if (GetProcessingSettings().tpcApplyClusterFilterOnCPU > 0 && (GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCClusterFinding || GetProcessingSettings().runMC)) { GPUError("tpcApplyClusterFilterOnCPU cannot be used with GPU clusterization or with MC labels"); return false; } @@ -332,9 +332,9 @@ int32_t GPUChainTracking::Init() const auto& threadContext = GetThreadContext(); if (GetProcessingSettings().debugLevel >= 1) { printf("Enabled Reconstruction Steps: 0x%x (on GPU: 0x%x)", (int32_t)GetRecoSteps().get(), (int32_t)GetRecoStepsGPU().get()); - for (uint32_t i = 0; i < sizeof(GPUDataTypes::RECO_STEP_NAMES) / sizeof(GPUDataTypes::RECO_STEP_NAMES[0]); i++) { + for (uint32_t i = 0; i < sizeof(gpudatatypes::RECO_STEP_NAMES) / sizeof(gpudatatypes::RECO_STEP_NAMES[0]); i++) { if (GetRecoSteps().isSet(1u << i)) { - printf(" - %s", GPUDataTypes::RECO_STEP_NAMES[i]); + printf(" - %s", gpudatatypes::RECO_STEP_NAMES[i]); if (GetRecoStepsGPU().isSet(1u << i)) { printf(" (G)"); } @@ -475,7 +475,7 @@ int32_t GPUChainTracking::ForceInitQA() qa.reset(new GPUQA(this)); } if (!GetQA()->IsInitialized()) { - return GetQA()->InitQA(GetProcessingSettings().runQA <= 0 ? -GetProcessingSettings().runQA : GPUQA::tasksAutomatic); + return GetQA()->InitQA(GetProcessingSettings().runQA <= 0 ? -GetProcessingSettings().runQA : gpudatatypes::gpuqa::tasksAutomatic); } return 0; } @@ -640,7 +640,7 @@ int32_t GPUChainTracking::DoQueuedUpdates(int32_t stream, bool updateSlave) pDst[i] = pSrc[i]; } } - if (mNewCalibObjects->trdGeometry && (GetRecoSteps() & GPUDataTypes::RecoStep::TRDTracking)) { + if (mNewCalibObjects->trdGeometry && (GetRecoSteps() & gpudatatypes::RecoStep::TRDTracking)) { if (GetProcessingSettings().trdTrackModelO2) { processors()->trdTrackerO2.UpdateGeometry(); if (mRec->IsGPU()) { @@ -690,7 +690,7 @@ int32_t GPUChainTracking::RunChain() } const bool needQA = GPUQA::QAAvailable() && (GetProcessingSettings().runQA || (GetProcessingSettings().eventDisplay && (mIOPtrs.nMCInfosTPC || GetProcessingSettings().runMC))); if (needQA && GetQA()->IsInitialized() == false) { - if (GetQA()->InitQA(GetProcessingSettings().runQA <= 0 ? -GetProcessingSettings().runQA : GPUQA::tasksAutomatic)) { + if (GetQA()->InitQA(GetProcessingSettings().runQA <= 0 ? -GetProcessingSettings().runQA : gpudatatypes::gpuqa::tasksAutomatic)) { return 1; } } @@ -1008,16 +1008,15 @@ void GPUChainTracking::SetO2Propagator(const o2::base::Propagator* prop) } } -void GPUChainTracking::ApplySyncSettings(GPUSettingsProcessing& proc, GPUSettingsRec& rec, GPUDataTypes::RecoStepField& steps, bool syncMode, int32_t dEdxMode) +void GPUChainTracking::ApplySyncSettings(GPUSettingsProcessing& proc, GPUSettingsRec& rec, gpudatatypes::RecoStepField& steps, bool syncMode, int32_t dEdxMode) { if (syncMode) { rec.useMatLUT = false; - rec.tpc.rebuildTrackMaxNonIntCov = 0.f; } if (proc.rtc.optSpecialCode == -1) { proc.rtc.optSpecialCode = syncMode; } if (dEdxMode != -2) { - steps.setBits(GPUDataTypes::RecoStep::TPCdEdx, dEdxMode == -1 ? !syncMode : dEdxMode > 0); + steps.setBits(gpudatatypes::RecoStep::TPCdEdx, dEdxMode == -1 ? !syncMode : dEdxMode > 0); } } diff --git a/GPU/GPUTracking/Global/GPUChainTracking.h b/GPU/GPUTracking/Global/GPUChainTracking.h index 7d70e0b667946..2dd1ece856ecf 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.h +++ b/GPU/GPUTracking/Global/GPUChainTracking.h @@ -16,7 +16,8 @@ #define GPUCHAINTRACKING_H #include "GPUChain.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" +#include "GPUDataTypesConfig.h" #include #include #include @@ -88,7 +89,7 @@ class GPUChainTracking : public GPUChain void ClearErrorCodes(bool cpuOnly = false); int32_t DoQueuedUpdates(int32_t stream, bool updateSlave = true); // Forces doing queue calib updates, don't call when you are not sure you are allowed to do so! bool QARanForTF() const { return mFractionalQAEnabled; } - static void ApplySyncSettings(GPUSettingsProcessing& proc, GPUSettingsRec& rec, GPUDataTypes::RecoStepField& steps, bool syncMode, int32_t dEdxMode = -2); + static void ApplySyncSettings(GPUSettingsProcessing& proc, GPUSettingsRec& rec, gpudatatypes::RecoStepField& steps, bool syncMode, int32_t dEdxMode = -2); // Structures for input and output data GPUTrackingInOutPointers& mIOPtrs; diff --git a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx index c4566ffb968a7..7629086272ed6 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx @@ -68,7 +68,7 @@ using namespace o2::dataformats; #ifdef GPUCA_TPC_GEOMETRY_O2 std::pair GPUChainTracking::TPCClusterizerDecodeZSCountUpdate(uint32_t iSector, const CfFragment& fragment) { - bool doGPU = mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding; + bool doGPU = mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCClusterFinding; GPUTPCClusterFinder& clusterer = processors()->tpcClusterer[iSector]; GPUTPCClusterFinder::ZSOffset* o = processors()->tpcClusterer[iSector].mPzsOffsets; uint32_t digits = 0; @@ -169,7 +169,7 @@ std::pair GPUChainTracking::TPCClusterizerDecodeZSCount(uint uint32_t nPages = 0; uint32_t endpointAdcSamples[GPUTrackingInOutZS::NENDPOINTS]; memset(endpointAdcSamples, 0, sizeof(endpointAdcSamples)); - bool doGPU = mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding; + bool doGPU = mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCClusterFinding; int32_t firstHBF = (mIOPtrs.settingsTF && mIOPtrs.settingsTF->hasTfStartOrbit) ? mIOPtrs.settingsTF->tfStartOrbit : ((mIOPtrs.tpcZS->sector[iSector].count[0] && mIOPtrs.tpcZS->sector[iSector].nZSPtr[0][0]) ? o2::raw::RDHUtils::getHeartBeatOrbit(*(const o2::header::RAWDataHeader*)mIOPtrs.tpcZS->sector[iSector].zsPtr[0][0]) : 0); for (uint16_t j = 0; j < GPUTrackingInOutZS::NENDPOINTS; j++) { @@ -475,7 +475,7 @@ std::pair GPUChainTracking::RunTPCClusterizer_transferZS(int int32_t GPUChainTracking::RunTPCClusterizer_prepare(bool restorePointers) { - bool doGPU = mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding; + bool doGPU = mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCClusterFinding; if (restorePointers) { for (uint32_t iSector = 0; iSector < NSECTORS; iSector++) { processors()->tpcClusterer[iSector].mPzsOffsets = mCFContext->ptrSave[iSector].zsOffsetHost; @@ -765,7 +765,7 @@ int32_t GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) std::unique_ptr tmpNativeClusterBuffer; const bool buildNativeGPU = doGPU && NeedTPCClustersOnGPU(); - const bool buildNativeHost = (mRec->GetRecoStepsOutputs() & GPUDataTypes::InOutType::TPCClusters) || GetProcessingSettings().deterministicGPUReconstruction; // TODO: Should do this also when clusters are needed for later steps on the host but not requested as output + const bool buildNativeHost = (mRec->GetRecoStepsOutputs() & gpudatatypes::InOutType::TPCClusters) || GetProcessingSettings().deterministicGPUReconstruction; // TODO: Should do this also when clusters are needed for later steps on the host but not requested as output const bool propagateMCLabels = buildNativeHost && GetProcessingSettings().runMC && processors()->ioPtrs.tpcPackedDigits && processors()->ioPtrs.tpcPackedDigits->tpcDigitsMC; const bool sortClusters = buildNativeHost && (GetProcessingSettings().deterministicGPUReconstruction || GetProcessingSettings().debugLevel >= 4); @@ -1277,7 +1277,7 @@ int32_t GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) } // Number of clusters is logged by tracking. This ensures clusters are still printed if it's not running - if (!(GetRecoSteps() & GPUDataTypes::RecoStep::TPCSectorTracking)) { + if (!(GetRecoSteps() & gpudatatypes::RecoStep::TPCSectorTracking)) { GPUInfo("Event has %zu TPC Clusters", nClsTotal); } diff --git a/GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx b/GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx index fab7179876c04..fd3c03a8b29ec 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx @@ -240,7 +240,7 @@ void GPUChainTracking::PrintOutputStat() } char trdText[1024] = ""; - if (GetRecoSteps() & GPUDataTypes::RecoStep::TRDTracking) { + if (GetRecoSteps() & gpudatatypes::RecoStep::TRDTracking) { int32_t nTRDTracks = 0; int32_t nTRDTracklets = 0; for (uint32_t k = 0; k < mIOPtrs.nTRDTracks; k++) { diff --git a/GPU/GPUTracking/Global/GPUChainTrackingTransformation.cxx b/GPU/GPUTracking/Global/GPUChainTrackingTransformation.cxx index 83ddc45830621..8b36c9520659e 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingTransformation.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingTransformation.cxx @@ -32,7 +32,7 @@ using namespace o2::tpc; bool GPUChainTracking::NeedTPCClustersOnGPU() { - return (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCConversion) || (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCSectorTracking) || (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCMerging) || (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCCompression); + return (mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCConversion) || (mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCSectorTracking) || (mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCMerging) || (mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCCompression); } int32_t GPUChainTracking::ConvertNativeToClusterData() @@ -41,7 +41,7 @@ int32_t GPUChainTracking::ConvertNativeToClusterData() const auto& threadContext = GetThreadContext(); bool transferClusters = false; - if (mRec->IsGPU() && !(mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding) && NeedTPCClustersOnGPU()) { + if (mRec->IsGPU() && !(mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCClusterFinding) && NeedTPCClustersOnGPU()) { mInputsHost->mNClusterNative = mInputsShadow->mNClusterNative = mIOPtrs.clustersNative->nClustersTotal; AllocateRegisteredMemory(mInputsHost->mResourceClusterNativeBuffer); processorsShadow()->ioPtrs.clustersNative = mInputsShadow->mPclusterNativeAccess; diff --git a/GPU/GPUTracking/Global/GPUErrors.cxx b/GPU/GPUTracking/Global/GPUErrors.cxx index 4baa299c6b976..dfe7a84f0f179 100644 --- a/GPU/GPUTracking/Global/GPUErrors.cxx +++ b/GPU/GPUTracking/Global/GPUErrors.cxx @@ -13,7 +13,7 @@ /// \author David Rohr #include "GPUErrors.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include "GPUCommonMath.h" #include "GPUDefMacros.h" #include "GPULogging.h" diff --git a/GPU/GPUTracking/Global/GPUTrackingInputProvider.cxx b/GPU/GPUTracking/Global/GPUTrackingInputProvider.cxx index 9bb8b230e9e0b..dc47b6c0a6663 100644 --- a/GPU/GPUTracking/Global/GPUTrackingInputProvider.cxx +++ b/GPU/GPUTracking/Global/GPUTrackingInputProvider.cxx @@ -13,7 +13,7 @@ /// \author David Rohr #include "GPUTrackingInputProvider.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include "GPUTRDTrackletWord.h" #include "GPUReconstruction.h" #include "GPUTPCClusterOccupancyMap.h" @@ -28,7 +28,7 @@ using namespace o2::tpc; void GPUTrackingInputProvider::InitializeProcessor() {} void* GPUTrackingInputProvider::SetPointersInputZS(void* mem) { - if (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding) { + if (mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCClusterFinding) { computePointerWithAlignment(mem, mPzsMeta); computePointerWithAlignment(mem, mPzsSizes, GPUTrackingInOutZS::NSECTORS * GPUTrackingInOutZS::NENDPOINTS); computePointerWithAlignment(mem, mPzsPtrs, GPUTrackingInOutZS::NSECTORS * GPUTrackingInOutZS::NENDPOINTS); @@ -101,7 +101,7 @@ void GPUTrackingInputProvider::RegisterMemoryAllocation() void GPUTrackingInputProvider::SetMaxData(const GPUTrackingInOutPointers& io) { - mHoldTPCZS = io.tpcZS && (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding); + mHoldTPCZS = io.tpcZS && (mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCClusterFinding); mHoldTPCClusterNative = (io.tpcZS || io.tpcPackedDigits || io.clustersNative || io.tpcCompressedClusters) && (mRec->IsGPU() || io.tpcCompressedClusters); mHoldTPCOccupancyMap = (io.tpcZS || io.tpcPackedDigits || io.clustersNative || io.tpcCompressedClusters) && (mRec->GetParam().rec.tpc.occupancyMapTimeBins || mRec->GetParam().rec.tpc.sysClusErrorC12Norm); mHoldTPCClusterNativeOutput = io.tpcZS || io.tpcPackedDigits || io.tpcCompressedClusters; diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.cxx b/GPU/GPUTracking/Interface/GPUO2Interface.cxx index 95a57a4b17c4b..ced3016dc15b1 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.cxx +++ b/GPU/GPUTracking/Interface/GPUO2Interface.cxx @@ -60,10 +60,10 @@ int32_t GPUO2Interface::Initialize(const GPUO2InterfaceConfiguration& config) mConfig.reset(new GPUO2InterfaceConfiguration(config)); mNContexts = mConfig->configProcessing.doublePipeline ? 2 : 1; mCtx.reset(new GPUO2Interface_processingContext[mNContexts]); - if (mConfig->configWorkflow.inputs.isSet(GPUDataTypes::InOutType::TPCRaw)) { + if (mConfig->configWorkflow.inputs.isSet(gpudatatypes::InOutType::TPCRaw)) { mConfig->configGRP.needsClusterer = 1; } - if (mConfig->configWorkflow.inputs.isSet(GPUDataTypes::InOutType::TPCCompressedClusters)) { + if (mConfig->configWorkflow.inputs.isSet(gpudatatypes::InOutType::TPCCompressedClusters)) { mConfig->configGRP.doCompClusterDecode = 1; } for (uint32_t i = 0; i < mNContexts; i++) { @@ -89,7 +89,7 @@ int32_t GPUO2Interface::Initialize(const GPUO2InterfaceConfiguration& config) mCtx[i].mRec->SetSettings(&mConfig->configGRP, &mConfig->configReconstruction, &mConfig->configProcessing, &mConfig->configWorkflow); mCtx[i].mChain->SetCalibObjects(mConfig->configCalib); - if (i == 0 && mConfig->configWorkflow.steps.isSet(GPUDataTypes::RecoStep::ITSTracking)) { + if (i == 0 && mConfig->configWorkflow.steps.isSet(gpudatatypes::RecoStep::ITSTracking)) { mChainITS = mCtx[i].mRec->AddChain(); } @@ -269,7 +269,7 @@ void GPUO2Interface::UseGPUPolynomialFieldInPropagator(o2::base::Propagator* pro prop->setGPUField(&mCtx[0].mRec->GetParam().polynomialField); } -void GPUO2Interface::ApplySyncSettings(GPUSettingsProcessing& proc, GPUSettingsRec& rec, GPUDataTypes::RecoStepField& steps, bool syncMode, int32_t dEdxMode) +void GPUO2Interface::ApplySyncSettings(GPUSettingsProcessing& proc, GPUSettingsRec& rec, gpudatatypes::RecoStepField& steps, bool syncMode, int32_t dEdxMode) { GPUChainTracking::ApplySyncSettings(proc, rec, steps, syncMode, dEdxMode); } diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.h b/GPU/GPUTracking/Interface/GPUO2Interface.h index 3b4dde2cb0f96..ca56018908b41 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.h +++ b/GPU/GPUTracking/Interface/GPUO2Interface.h @@ -17,7 +17,8 @@ #include "GPUO2ExternalUser.h" #include "GPUCommonDef.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" +#include "GPUDataTypesConfig.h" #include #include @@ -82,7 +83,7 @@ class GPUO2Interface // Updates all calibration objects that are != nullptr in newCalib int32_t UpdateCalibration(const GPUCalibObjectsConst& newCalib, const GPUNewCalibValues& newVals, uint32_t iThread = 0); - static void ApplySyncSettings(GPUSettingsProcessing& proc, GPUSettingsRec& rec, GPUDataTypes::RecoStepField& steps, bool syncMode, int32_t dEdxMode = -2); + static void ApplySyncSettings(GPUSettingsProcessing& proc, GPUSettingsRec& rec, gpudatatypes::RecoStepField& steps, bool syncMode, int32_t dEdxMode = -2); int32_t registerMemoryForGPU(const void* ptr, size_t size); int32_t unregisterMemoryForGPU(const void* ptr); diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.cxx b/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.cxx index 54477f550b3d4..606f2bfc829e5 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.cxx +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.cxx @@ -13,7 +13,7 @@ /// \author David Rohr #include "GPUO2InterfaceConfiguration.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" using namespace o2::gpu; diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h b/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h index f378fc2c4fb7b..0f8a3784f0a88 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h @@ -17,7 +17,7 @@ #include "GPUO2ExternalUser.h" #include "GPUSettings.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include "GPUHostDataTypes.h" #include "GPUOutputControl.h" #include "DataFormatsTPC/Constants.h" diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.h b/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.h index a7e9d309b6d3d..c0946bab0076d 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.h +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceDisplay.h @@ -18,7 +18,7 @@ #include "GPUO2ExternalUser.h" #include #include -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" namespace o2::gpu { diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx index 8793f3bb399c8..260781c17406b 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx @@ -420,7 +420,7 @@ void* GPUTPCGMMerger::SetPointersMemory(void* mem) void* GPUTPCGMMerger::SetPointersRefitScratch(void* mem) { computePointerWithAlignment(mem, mTrackOrderAttach, mNMaxTracks); - const bool mergerSortTracks = mRec->GetProcessingSettings().mergerSortTracks == -1 ? mRec->getGPUParameters(mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCMerging).par_SORT_BEFORE_FIT : mRec->GetProcessingSettings().mergerSortTracks; + const bool mergerSortTracks = mRec->GetProcessingSettings().mergerSortTracks == -1 ? mRec->getGPUParameters(mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCMerging).par_SORT_BEFORE_FIT : mRec->GetProcessingSettings().mergerSortTracks; if (mergerSortTracks) { computePointerWithAlignment(mem, mTrackOrderProcess, mNMaxTracks); } @@ -443,7 +443,7 @@ void* GPUTPCGMMerger::SetPointersOutput(void* mem) void* GPUTPCGMMerger::SetPointersOutputState(void* mem) { - if ((mRec->GetRecoSteps() & GPUDataTypes::RecoStep::Refit) || mRec->GetProcessingSettings().outputSharedClusterMap) { + if ((mRec->GetRecoSteps() & gpudatatypes::RecoStep::Refit) || mRec->GetProcessingSettings().outputSharedClusterMap) { computePointerWithAlignment(mem, mClusterStateExt, mNMaxClusters); } else { mClusterStateExt = nullptr; @@ -515,7 +515,7 @@ void GPUTPCGMMerger::SetMaxData(const GPUTrackingInOutPointers& io) } if (io.clustersNative) { mNMaxClusters = io.clustersNative->nClustersTotal; - } else if (mRec->GetRecoSteps() & GPUDataTypes::RecoStep::TPCSectorTracking) { + } else if (mRec->GetRecoSteps() & gpudatatypes::RecoStep::TPCSectorTracking) { mNMaxClusters = 0; for (int32_t i = 0; i < NSECTORS; i++) { mNMaxClusters += mRec->GetConstantMem().tpcTrackers[i].NHitsTotal(); @@ -533,7 +533,7 @@ int32_t GPUTPCGMMerger::CheckSectors() throw std::runtime_error("mNMaxSingleSectorTracks too small"); } } - if (!(mRec->GetRecoSteps() & GPUDataTypes::RecoStep::TPCSectorTracking)) { + if (!(mRec->GetRecoSteps() & gpudatatypes::RecoStep::TPCSectorTracking)) { throw std::runtime_error("Must run also sector tracking"); } return 0; diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.h b/GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.h index dec72b1d431e6..5d00451516aa8 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.h @@ -24,7 +24,7 @@ namespace o2::gpu class GPUTPCGMMergerGeneral : public GPUKernelTemplate { public: - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TPCMerging; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::TPCMerging; } typedef GPUTPCGMMerger processorType; GPUhdi() static processorType* Processor(GPUConstantMem& processors) { diff --git a/GPU/GPUTracking/Merger/GPUTPCGlobalDebugSortKernels.h b/GPU/GPUTracking/Merger/GPUTPCGlobalDebugSortKernels.h index 726e8cee1f7a7..87204449749b6 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGlobalDebugSortKernels.h +++ b/GPU/GPUTracking/Merger/GPUTPCGlobalDebugSortKernels.h @@ -32,7 +32,7 @@ class GPUTPCGlobalDebugSortKernels : public GPUKernelTemplate mergedTracks1 = 2, mergedTracks2 = 3, borderTracks = 4 }; - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TPCMerging; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::TPCMerging; } typedef GPUTPCGMMerger processorType; GPUhdi() static processorType* Processor(GPUConstantMem& processors) { return &processors.tpcMerger; } diff --git a/GPU/GPUTracking/Refit/GPUTrackingRefitKernel.h b/GPU/GPUTracking/Refit/GPUTrackingRefitKernel.h index 9b99ffb8402c0..a397e349d29fb 100644 --- a/GPU/GPUTracking/Refit/GPUTrackingRefitKernel.h +++ b/GPU/GPUTracking/Refit/GPUTrackingRefitKernel.h @@ -24,7 +24,7 @@ namespace o2::gpu class GPUTrackingRefitKernel : public GPUKernelTemplate { public: - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TPCCompression; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::TPCCompression; } enum K : int32_t { mode0asGPU = 0, diff --git a/GPU/GPUTracking/SectorTracker/GPUTPCCreateOccupancyMap.h b/GPU/GPUTracking/SectorTracker/GPUTPCCreateOccupancyMap.h index de8eb8622adb1..2faf0ec668a6f 100644 --- a/GPU/GPUTracking/SectorTracker/GPUTPCCreateOccupancyMap.h +++ b/GPU/GPUTracking/SectorTracker/GPUTPCCreateOccupancyMap.h @@ -29,7 +29,7 @@ class GPUTPCCreateOccupancyMap : public GPUKernelTemplate enum K { defaultKernel = 0, fill = 0, fold = 1 }; - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TPCSectorTracking; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::TPCSectorTracking; } template GPUd() static void Thread(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUsharedref() GPUSharedMemory& smem, processorType& processors, Args... args); }; diff --git a/GPU/GPUTracking/SectorTracker/GPUTPCCreateTrackingData.h b/GPU/GPUTracking/SectorTracker/GPUTPCCreateTrackingData.h index dc1beacf79d02..8085124653332 100644 --- a/GPU/GPUTracking/SectorTracker/GPUTPCCreateTrackingData.h +++ b/GPU/GPUTracking/SectorTracker/GPUTPCCreateTrackingData.h @@ -32,7 +32,7 @@ class GPUTPCCreateTrackingData : public GPUKernelTemplate }; typedef GPUconstantref() GPUTPCTracker processorType; - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TPCSectorTracking; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::TPCSectorTracking; } GPUhdi() static processorType* Processor(GPUConstantMem& processors) { return processors.tpcTrackers; diff --git a/GPU/GPUTracking/SectorTracker/GPUTPCExtrapolationTracking.cxx b/GPU/GPUTracking/SectorTracker/GPUTPCExtrapolationTracking.cxx index eaaefcb278ffe..ee403116cc6da 100644 --- a/GPU/GPUTracking/SectorTracker/GPUTPCExtrapolationTracking.cxx +++ b/GPU/GPUTracking/SectorTracker/GPUTPCExtrapolationTracking.cxx @@ -167,11 +167,11 @@ GPUdii() void GPUTPCExtrapolationTracking::Thread<0>(int32_t nBlocks, int32_t nT return; } const int32_t iSector = tracker.ISector(); - int32_t sectorLeft = (iSector + (GPUDataTypes::NSECTORS / 2 - 1)) % (GPUDataTypes::NSECTORS / 2); - int32_t sectorRight = (iSector + 1) % (GPUDataTypes::NSECTORS / 2); - if (iSector >= (int32_t)GPUDataTypes::NSECTORS / 2) { - sectorLeft += GPUDataTypes::NSECTORS / 2; - sectorRight += GPUDataTypes::NSECTORS / 2; + int32_t sectorLeft = (iSector + (gpudatatypes::NSECTORS / 2 - 1)) % (gpudatatypes::NSECTORS / 2); + int32_t sectorRight = (iSector + 1) % (gpudatatypes::NSECTORS / 2); + if (iSector >= (int32_t)gpudatatypes::NSECTORS / 2) { + sectorLeft += gpudatatypes::NSECTORS / 2; + sectorRight += gpudatatypes::NSECTORS / 2; } PerformExtrapolationTracking(nBlocks, nThreads, iBlock, iThread, tracker.GetConstantMem()->tpcTrackers[sectorLeft], smem, tracker, true); PerformExtrapolationTracking(nBlocks, nThreads, iBlock, iThread, tracker.GetConstantMem()->tpcTrackers[sectorRight], smem, tracker, false); @@ -180,22 +180,22 @@ GPUdii() void GPUTPCExtrapolationTracking::Thread<0>(int32_t nBlocks, int32_t nT GPUd() int32_t GPUTPCExtrapolationTracking::ExtrapolationTrackingSectorOrder(int32_t iSector) { iSector++; - if (iSector == GPUDataTypes::NSECTORS / 2) { + if (iSector == gpudatatypes::NSECTORS / 2) { iSector = 0; } - if (iSector == GPUDataTypes::NSECTORS) { - iSector = GPUDataTypes::NSECTORS / 2; + if (iSector == gpudatatypes::NSECTORS) { + iSector = gpudatatypes::NSECTORS / 2; } return iSector; } GPUd() void GPUTPCExtrapolationTracking::ExtrapolationTrackingSectorLeftRight(uint32_t iSector, uint32_t& left, uint32_t& right) { - left = (iSector + (GPUDataTypes::NSECTORS / 2 - 1)) % (GPUDataTypes::NSECTORS / 2); - right = (iSector + 1) % (GPUDataTypes::NSECTORS / 2); - if (iSector >= (int32_t)GPUDataTypes::NSECTORS / 2) { - left += GPUDataTypes::NSECTORS / 2; - right += GPUDataTypes::NSECTORS / 2; + left = (iSector + (gpudatatypes::NSECTORS / 2 - 1)) % (gpudatatypes::NSECTORS / 2); + right = (iSector + 1) % (gpudatatypes::NSECTORS / 2); + if (iSector >= (int32_t)gpudatatypes::NSECTORS / 2) { + left += gpudatatypes::NSECTORS / 2; + right += gpudatatypes::NSECTORS / 2; } } diff --git a/GPU/GPUTracking/SectorTracker/GPUTPCExtrapolationTracking.h b/GPU/GPUTracking/SectorTracker/GPUTPCExtrapolationTracking.h index 91a33d132f136..9e39ba0ce258d 100644 --- a/GPU/GPUTracking/SectorTracker/GPUTPCExtrapolationTracking.h +++ b/GPU/GPUTracking/SectorTracker/GPUTPCExtrapolationTracking.h @@ -30,7 +30,7 @@ class GPUTPCExtrapolationTracking : public GPUKernelTemplate }; typedef GPUconstantref() GPUTPCTracker processorType; - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TPCSectorTracking; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::TPCSectorTracking; } GPUhdi() static processorType* Processor(GPUConstantMem& processors) { return processors.tpcTrackers; @@ -50,7 +50,7 @@ class GPUTPCExtrapolationTrackingCopyNumbers : public GPUKernelTemplate { public: typedef GPUconstantref() GPUTPCTracker processorType; - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TPCSectorTracking; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::TPCSectorTracking; } GPUhdi() static processorType* Processor(GPUConstantMem& processors) { return processors.tpcTrackers; diff --git a/GPU/GPUTracking/SectorTracker/GPUTPCNeighboursCleaner.h b/GPU/GPUTracking/SectorTracker/GPUTPCNeighboursCleaner.h index de79b268aea78..2caf09e4886df 100644 --- a/GPU/GPUTracking/SectorTracker/GPUTPCNeighboursCleaner.h +++ b/GPU/GPUTracking/SectorTracker/GPUTPCNeighboursCleaner.h @@ -38,7 +38,7 @@ class GPUTPCNeighboursCleaner : public GPUKernelTemplate }; typedef GPUconstantref() GPUTPCTracker processorType; - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TPCSectorTracking; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::TPCSectorTracking; } GPUhdi() static processorType* Processor(GPUConstantMem& processors) { return processors.tpcTrackers; diff --git a/GPU/GPUTracking/SectorTracker/GPUTPCNeighboursFinder.h b/GPU/GPUTracking/SectorTracker/GPUTPCNeighboursFinder.h index 6bdc637b6bad6..ea574b5576d37 100644 --- a/GPU/GPUTracking/SectorTracker/GPUTPCNeighboursFinder.h +++ b/GPU/GPUTracking/SectorTracker/GPUTPCNeighboursFinder.h @@ -48,7 +48,7 @@ class GPUTPCNeighboursFinder : public GPUKernelTemplate }; typedef GPUconstantref() GPUTPCTracker processorType; - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TPCSectorTracking; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::TPCSectorTracking; } GPUhdi() static processorType* Processor(GPUConstantMem& processors) { return processors.tpcTrackers; diff --git a/GPU/GPUTracking/SectorTracker/GPUTPCSectorDebugSortKernels.h b/GPU/GPUTracking/SectorTracker/GPUTPCSectorDebugSortKernels.h index 520a791b0eb43..8b994be687e72 100644 --- a/GPU/GPUTracking/SectorTracker/GPUTPCSectorDebugSortKernels.h +++ b/GPU/GPUTracking/SectorTracker/GPUTPCSectorDebugSortKernels.h @@ -30,7 +30,7 @@ class GPUTPCSectorDebugSortKernels : public GPUKernelTemplate hitData = 0, startHits = 1, sectorTracks = 2 }; - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TPCSectorTracking; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::TPCSectorTracking; } typedef GPUTPCTracker processorType; GPUhdi() static processorType* Processor(GPUConstantMem& processors) { return processors.tpcTrackers; } diff --git a/GPU/GPUTracking/SectorTracker/GPUTPCStartHitsFinder.h b/GPU/GPUTracking/SectorTracker/GPUTPCStartHitsFinder.h index c834b17369f0f..c62eeb315b1f8 100644 --- a/GPU/GPUTracking/SectorTracker/GPUTPCStartHitsFinder.h +++ b/GPU/GPUTracking/SectorTracker/GPUTPCStartHitsFinder.h @@ -38,7 +38,7 @@ class GPUTPCStartHitsFinder : public GPUKernelTemplate }; typedef GPUconstantref() GPUTPCTracker processorType; - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TPCSectorTracking; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::TPCSectorTracking; } GPUhdi() static processorType* Processor(GPUConstantMem& processors) { return processors.tpcTrackers; diff --git a/GPU/GPUTracking/SectorTracker/GPUTPCStartHitsSorter.h b/GPU/GPUTracking/SectorTracker/GPUTPCStartHitsSorter.h index 0e2fd96dd2690..1cee79d292b84 100644 --- a/GPU/GPUTracking/SectorTracker/GPUTPCStartHitsSorter.h +++ b/GPU/GPUTracking/SectorTracker/GPUTPCStartHitsSorter.h @@ -38,7 +38,7 @@ class GPUTPCStartHitsSorter : public GPUKernelTemplate }; typedef GPUconstantref() GPUTPCTracker processorType; - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TPCSectorTracking; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::TPCSectorTracking; } GPUhdi() static processorType* Processor(GPUConstantMem& processors) { return processors.tpcTrackers; diff --git a/GPU/GPUTracking/SectorTracker/GPUTPCTracker.cxx b/GPU/GPUTracking/SectorTracker/GPUTPCTracker.cxx index c5e6a21460a36..03931f73a4a12 100644 --- a/GPU/GPUTracking/SectorTracker/GPUTPCTracker.cxx +++ b/GPU/GPUTracking/SectorTracker/GPUTPCTracker.cxx @@ -53,7 +53,7 @@ void GPUTPCTracker::InitializeProcessor() void* GPUTPCTracker::SetPointersDataLinks(void* mem) { return mData.SetPointersLinks(mem); } void* GPUTPCTracker::SetPointersDataWeights(void* mem) { return mData.SetPointersWeights(mem); } -void* GPUTPCTracker::SetPointersDataScratch(void* mem) { return mData.SetPointersScratch(mem, mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCMerging); } +void* GPUTPCTracker::SetPointersDataScratch(void* mem) { return mData.SetPointersScratch(mem, mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCMerging); } void* GPUTPCTracker::SetPointersDataRows(void* mem) { return mData.SetPointersRows(mem); } void* GPUTPCTracker::SetPointersScratch(void* mem) @@ -62,7 +62,7 @@ void* GPUTPCTracker::SetPointersScratch(void* mem) if (mRec->GetProcessingSettings().memoryAllocationStrategy != GPUMemoryResource::ALLOCATION_INDIVIDUAL) { mem = SetPointersTracklets(mem); } - if (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCSectorTracking) { + if (mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCSectorTracking) { computePointerWithAlignment(mem, mTrackletTmpStartHits, GPUCA_ROW_COUNT * mNMaxRowStartHits); computePointerWithAlignment(mem, mRowStartHitCountOffset, GPUCA_ROW_COUNT); } @@ -74,7 +74,7 @@ void* GPUTPCTracker::SetPointersScratchHost(void* mem) if (mRec->GetProcessingSettings().keepDisplayMemory) { computePointerWithAlignment(mem, mLinkTmpMemory, mRec->Res(mMemoryResLinks).Size()); } - mem = mData.SetPointersClusterIds(mem, mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCMerging); + mem = mData.SetPointersClusterIds(mem, mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCMerging); return mem; } @@ -86,7 +86,7 @@ void* GPUTPCTracker::SetPointersCommon(void* mem) bool GPUTPCTracker::MemoryReuseAllowed() { - return !mRec->GetProcessingSettings().keepDisplayMemory && ((mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCSectorTracking) || mRec->GetProcessingSettings().inKernelParallel == 1 || mRec->GetProcessingSettings().nHostThreads == 1); + return !mRec->GetProcessingSettings().keepDisplayMemory && ((mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCSectorTracking) || mRec->GetProcessingSettings().inKernelParallel == 1 || mRec->GetProcessingSettings().nHostThreads == 1); } void GPUTPCTracker::RegisterMemoryAllocation() @@ -158,7 +158,7 @@ void GPUTPCTracker::SetMaxData(const GPUTrackingInOutPointers& io) } mNMaxTrackHits = mRec->MemoryScalers()->NTPCSectorTrackHits(mData.NumberOfHits(), mRec->GetProcessingSettings().tpcInputWithClusterRejection); - if (mRec->getGPUParameters(mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCSectorTracking).par_SORT_STARTHITS) { + if (mRec->getGPUParameters(mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCSectorTracking).par_SORT_STARTHITS) { if (mNMaxStartHits > mNMaxRowStartHits * GPUCA_ROW_COUNT) { mNMaxStartHits = mNMaxRowStartHits * GPUCA_ROW_COUNT; } diff --git a/GPU/GPUTracking/SectorTracker/GPUTPCTrackletConstructor.h b/GPU/GPUTracking/SectorTracker/GPUTPCTrackletConstructor.h index 031c32b2b4334..120797ad4f1eb 100644 --- a/GPU/GPUTracking/SectorTracker/GPUTPCTrackletConstructor.h +++ b/GPU/GPUTracking/SectorTracker/GPUTPCTrackletConstructor.h @@ -85,7 +85,7 @@ class GPUTPCTrackletConstructor : public GPUKernelTemplate GPUd() static int32_t GPUTPCTrackletConstructorExtrapolationTracking(GPUconstantref() GPUTPCTracker& tracker, GPUsharedref() T& sMem, GPUTPCTrackParam& tParam, int32_t startrow, int32_t increment, int32_t iTracklet, calink* rowHits); typedef GPUconstantref() GPUTPCTracker processorType; - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TPCSectorTracking; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::TPCSectorTracking; } GPUhdi() static processorType* Processor(GPUConstantMem& processors) { return processors.tpcTrackers; diff --git a/GPU/GPUTracking/SectorTracker/GPUTPCTrackletSelector.h b/GPU/GPUTracking/SectorTracker/GPUTPCTrackletSelector.h index 070e02fad8222..6a4a7d9013e5a 100644 --- a/GPU/GPUTracking/SectorTracker/GPUTPCTrackletSelector.h +++ b/GPU/GPUTracking/SectorTracker/GPUTPCTrackletSelector.h @@ -41,7 +41,7 @@ class GPUTPCTrackletSelector : public GPUKernelTemplate }; typedef GPUconstantref() GPUTPCTracker processorType; - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TPCSectorTracking; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::TPCSectorTracking; } GPUhdi() static processorType* Processor(GPUConstantMem& processors) { return processors.tpcTrackers; diff --git a/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx b/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx index 1b3603a226af0..b9825bc6da481 100644 --- a/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx +++ b/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx @@ -371,45 +371,45 @@ int32_t SetupReconstruction() procSet.runMC = true; } - steps.steps = GPUDataTypes::RecoStep::AllRecoSteps; + steps.steps = gpudatatypes::RecoStep::AllRecoSteps; if (configStandalone.runTRD != -1) { - steps.steps.setBits(GPUDataTypes::RecoStep::TRDTracking, configStandalone.runTRD > 0); + steps.steps.setBits(gpudatatypes::RecoStep::TRDTracking, configStandalone.runTRD > 0); } else if (chainTracking->GetTRDGeometry() == nullptr) { - steps.steps.setBits(GPUDataTypes::RecoStep::TRDTracking, false); + steps.steps.setBits(gpudatatypes::RecoStep::TRDTracking, false); } if (configStandalone.runCompression != -1) { - steps.steps.setBits(GPUDataTypes::RecoStep::TPCCompression, configStandalone.runCompression > 0); + steps.steps.setBits(gpudatatypes::RecoStep::TPCCompression, configStandalone.runCompression > 0); } if (configStandalone.runTransformation != -1) { - steps.steps.setBits(GPUDataTypes::RecoStep::TPCConversion, configStandalone.runTransformation > 0); + steps.steps.setBits(gpudatatypes::RecoStep::TPCConversion, configStandalone.runTransformation > 0); } - steps.steps.setBits(GPUDataTypes::RecoStep::Refit, configStandalone.runRefit); + steps.steps.setBits(gpudatatypes::RecoStep::Refit, configStandalone.runRefit); if (!configStandalone.runMerger) { - steps.steps.setBits(GPUDataTypes::RecoStep::TPCMerging, false); - steps.steps.setBits(GPUDataTypes::RecoStep::TRDTracking, false); - steps.steps.setBits(GPUDataTypes::RecoStep::TPCdEdx, false); - steps.steps.setBits(GPUDataTypes::RecoStep::TPCCompression, false); - steps.steps.setBits(GPUDataTypes::RecoStep::Refit, false); + steps.steps.setBits(gpudatatypes::RecoStep::TPCMerging, false); + steps.steps.setBits(gpudatatypes::RecoStep::TRDTracking, false); + steps.steps.setBits(gpudatatypes::RecoStep::TPCdEdx, false); + steps.steps.setBits(gpudatatypes::RecoStep::TPCCompression, false); + steps.steps.setBits(gpudatatypes::RecoStep::Refit, false); } if (configStandalone.TF.bunchSim || configStandalone.TF.nMerge) { - steps.steps.setBits(GPUDataTypes::RecoStep::TRDTracking, false); + steps.steps.setBits(gpudatatypes::RecoStep::TRDTracking, false); } - steps.inputs.set(GPUDataTypes::InOutType::TPCClusters, GPUDataTypes::InOutType::TRDTracklets); - steps.steps.setBits(GPUDataTypes::RecoStep::TPCDecompression, false); - steps.inputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, false); + steps.inputs.set(gpudatatypes::InOutType::TPCClusters, gpudatatypes::InOutType::TRDTracklets); + steps.steps.setBits(gpudatatypes::RecoStep::TPCDecompression, false); + steps.inputs.setBits(gpudatatypes::InOutType::TPCCompressedClusters, false); if (grp.doCompClusterDecode) { - steps.inputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, true); - steps.inputs.setBits(GPUDataTypes::InOutType::TPCClusters, false); - steps.steps.setBits(GPUDataTypes::RecoStep::TPCCompression, false); - steps.steps.setBits(GPUDataTypes::RecoStep::TPCClusterFinding, false); - steps.steps.setBits(GPUDataTypes::RecoStep::TPCDecompression, true); - steps.outputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, false); + steps.inputs.setBits(gpudatatypes::InOutType::TPCCompressedClusters, true); + steps.inputs.setBits(gpudatatypes::InOutType::TPCClusters, false); + steps.steps.setBits(gpudatatypes::RecoStep::TPCCompression, false); + steps.steps.setBits(gpudatatypes::RecoStep::TPCClusterFinding, false); + steps.steps.setBits(gpudatatypes::RecoStep::TPCDecompression, true); + steps.outputs.setBits(gpudatatypes::InOutType::TPCCompressedClusters, false); } else if (grp.needsClusterer) { - steps.inputs.setBits(GPUDataTypes::InOutType::TPCRaw, true); - steps.inputs.setBits(GPUDataTypes::InOutType::TPCClusters, false); + steps.inputs.setBits(gpudatatypes::InOutType::TPCRaw, true); + steps.inputs.setBits(gpudatatypes::InOutType::TPCClusters, false); } else { - steps.steps.setBits(GPUDataTypes::RecoStep::TPCClusterFinding, false); + steps.steps.setBits(gpudatatypes::RecoStep::TPCClusterFinding, false); } if (configStandalone.recoSteps >= 0) { @@ -420,12 +420,12 @@ int32_t SetupReconstruction() } steps.outputs.clear(); - steps.outputs.setBits(GPUDataTypes::InOutType::TPCMergedTracks, steps.steps.isSet(GPUDataTypes::RecoStep::TPCMerging)); - steps.outputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, steps.steps.isSet(GPUDataTypes::RecoStep::TPCCompression)); - steps.outputs.setBits(GPUDataTypes::InOutType::TRDTracks, steps.steps.isSet(GPUDataTypes::RecoStep::TRDTracking)); - steps.outputs.setBits(GPUDataTypes::InOutType::TPCClusters, steps.steps.isSet(GPUDataTypes::RecoStep::TPCClusterFinding)); + steps.outputs.setBits(gpudatatypes::InOutType::TPCMergedTracks, steps.steps.isSet(gpudatatypes::RecoStep::TPCMerging)); + steps.outputs.setBits(gpudatatypes::InOutType::TPCCompressedClusters, steps.steps.isSet(gpudatatypes::RecoStep::TPCCompression)); + steps.outputs.setBits(gpudatatypes::InOutType::TRDTracks, steps.steps.isSet(gpudatatypes::RecoStep::TRDTracking)); + steps.outputs.setBits(gpudatatypes::InOutType::TPCClusters, steps.steps.isSet(gpudatatypes::RecoStep::TPCClusterFinding)); - if (steps.steps.isSet(GPUDataTypes::RecoStep::TRDTracking)) { + if (steps.steps.isSet(gpudatatypes::RecoStep::TRDTracking)) { if (procSet.createO2Output && !procSet.trdTrackModelO2) { procSet.createO2Output = 1; // Must not be 2, to make sure TPC GPU tracks are still available for TRD } @@ -447,14 +447,14 @@ int32_t SetupReconstruction() } if (configStandalone.testSyncAsync) { // TODO: Add --async mode / flag // Set settings for asynchronous - steps.steps.setBits(GPUDataTypes::RecoStep::TPCDecompression, true); - steps.steps.setBits(GPUDataTypes::RecoStep::TPCdEdx, true); - steps.steps.setBits(GPUDataTypes::RecoStep::TPCCompression, false); - steps.steps.setBits(GPUDataTypes::RecoStep::TPCClusterFinding, false); - steps.inputs.setBits(GPUDataTypes::InOutType::TPCRaw, false); - steps.inputs.setBits(GPUDataTypes::InOutType::TPCClusters, false); - steps.inputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, true); - steps.outputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, false); + steps.steps.setBits(gpudatatypes::RecoStep::TPCDecompression, true); + steps.steps.setBits(gpudatatypes::RecoStep::TPCdEdx, true); + steps.steps.setBits(gpudatatypes::RecoStep::TPCCompression, false); + steps.steps.setBits(gpudatatypes::RecoStep::TPCClusterFinding, false); + steps.inputs.setBits(gpudatatypes::InOutType::TPCRaw, false); + steps.inputs.setBits(gpudatatypes::InOutType::TPCClusters, false); + steps.inputs.setBits(gpudatatypes::InOutType::TPCCompressedClusters, true); + steps.outputs.setBits(gpudatatypes::InOutType::TPCCompressedClusters, false); procSet.runMC = false; procSet.runQA = runAsyncQA; procSet.eventDisplay = eventDisplay.get(); @@ -724,7 +724,7 @@ int32_t main(int argc, char** argv) eventsDir = std::string(configStandalone.absoluteEventsDir ? "" : "events/") + configStandalone.eventsDir + "/"; GPUSettingsDeviceBackend deviceSet; - deviceSet.deviceType = configStandalone.runGPU ? GPUDataTypes::GetDeviceType(configStandalone.gpuType.c_str()) : GPUDataTypes::DeviceType::CPU; + deviceSet.deviceType = configStandalone.runGPU ? gpudatatypes::GetDeviceType(configStandalone.gpuType.c_str()) : gpudatatypes::DeviceType::CPU; deviceSet.forceDeviceType = configStandalone.runGPUforce; deviceSet.master = nullptr; recUnique.reset(GPUReconstruction::CreateInstance(deviceSet)); diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChainContext.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChainContext.h index 2344c089a4436..40dd379eae30a 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChainContext.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChainContext.h @@ -16,7 +16,7 @@ #define O2_GPU_TPCCFCHAINCONTEXT_H #include "clusterFinderDefs.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include "GPUTPCClusterFinder.h" #include "CfFragment.h" #include diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChargeMapFiller.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChargeMapFiller.h index 800ba786c2105..3ca6b52238ed7 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChargeMapFiller.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFChargeMapFiller.h @@ -47,9 +47,9 @@ class GPUTPCCFChargeMapFiller : public GPUKernelTemplate return processors.tpcClusterer; } - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { - return GPUDataTypes::RecoStep::TPCClusterFinding; + return gpudatatypes::RecoStep::TPCClusterFinding; } template diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.h index 2403aa6d29ecd..25c93a4649662 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.h @@ -43,9 +43,9 @@ class GPUTPCCFCheckPadBaseline : public GPUKernelTemplate return processors.tpcClusterer; } - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { - return GPUDataTypes::RecoStep::TPCClusterFinding; + return gpudatatypes::RecoStep::TPCClusterFinding; } template diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.h index 70e21db81756c..09814b464651c 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFClusterizer.h @@ -49,9 +49,9 @@ class GPUTPCCFClusterizer : public GPUKernelTemplate return processors.tpcClusterer; } - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { - return GPUDataTypes::RecoStep::TPCClusterFinding; + return gpudatatypes::RecoStep::TPCClusterFinding; } template diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDecodeZS.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDecodeZS.h index c633a5ebc2774..b8ff90f511057 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDecodeZS.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDecodeZS.h @@ -53,9 +53,9 @@ class GPUTPCCFDecodeZS : public GPUKernelTemplate return processors.tpcClusterer; } - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { - return GPUDataTypes::RecoStep::TPCClusterFinding; + return gpudatatypes::RecoStep::TPCClusterFinding; } template @@ -72,9 +72,9 @@ class GPUTPCCFDecodeZSLinkBase : public GPUKernelTemplate return processors.tpcClusterer; } - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { - return GPUDataTypes::RecoStep::TPCClusterFinding; + return gpudatatypes::RecoStep::TPCClusterFinding; } struct DecodeCtx { diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.h index 902e3a28fd21b..2debce3dc0d6c 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.h @@ -42,9 +42,9 @@ class GPUTPCCFDeconvolution : public GPUKernelTemplate return processors.tpcClusterer; } - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { - return GPUDataTypes::RecoStep::TPCClusterFinding; + return gpudatatypes::RecoStep::TPCClusterFinding; } template diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFGather.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFGather.h index 210853237b86e..50fbe63eb6dac 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFGather.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFGather.h @@ -32,9 +32,9 @@ class GPUTPCCFGather : public GPUKernelTemplate return processors.tpcClusterer; } - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { - return GPUDataTypes::RecoStep::TPCClusterFinding; + return gpudatatypes::RecoStep::TPCClusterFinding; } template diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFMCLabelFlattener.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFMCLabelFlattener.h index 6bdec7760527c..cc39938b70d21 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFMCLabelFlattener.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFMCLabelFlattener.h @@ -44,9 +44,9 @@ class GPUTPCCFMCLabelFlattener : public GPUKernelTemplate return processors.tpcClusterer; } - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { - return GPUDataTypes::RecoStep::TPCClusterFinding; + return gpudatatypes::RecoStep::TPCClusterFinding; } template diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFNoiseSuppression.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFNoiseSuppression.h index 59196da11079b..27095bb17c1e9 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFNoiseSuppression.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFNoiseSuppression.h @@ -48,9 +48,9 @@ class GPUTPCCFNoiseSuppression : public GPUKernelTemplate return processors.tpcClusterer; } - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { - return GPUDataTypes::RecoStep::TPCClusterFinding; + return gpudatatypes::RecoStep::TPCClusterFinding; } template diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.h index e480518ddc9dd..eeda0cecb3bc3 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.h @@ -42,9 +42,9 @@ class GPUTPCCFPeakFinder : public GPUKernelTemplate return processors.tpcClusterer; } - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { - return GPUDataTypes::RecoStep::TPCClusterFinding; + return gpudatatypes::RecoStep::TPCClusterFinding; } template diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.h index a5ea8b24e9522..3b9b7e2b8329a 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.h @@ -51,9 +51,9 @@ class GPUTPCCFStreamCompaction : public GPUKernelTemplate return processors.tpcClusterer; } - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { - return GPUDataTypes::RecoStep::TPCClusterFinding; + return gpudatatypes::RecoStep::TPCClusterFinding; } template diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.cxx index 541edaa689c6c..44b005eb20233 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.cxx @@ -48,7 +48,7 @@ void* GPUTPCClusterFinder::SetPointersMemory(void* mem) void* GPUTPCClusterFinder::SetPointersInput(void* mem) { - if (mNMaxPages == 0 && (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding)) { + if (mNMaxPages == 0 && (mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCClusterFinding)) { computePointerWithAlignment(mem, mPdigits, mNMaxDigits); } return mem; @@ -56,7 +56,7 @@ void* GPUTPCClusterFinder::SetPointersInput(void* mem) void* GPUTPCClusterFinder::SetPointersZSOffset(void* mem) { - const int32_t n = (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding) ? mNMaxPages : GPUTrackingInOutZS::NENDPOINTS; + const int32_t n = (mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCClusterFinding) ? mNMaxPages : GPUTrackingInOutZS::NENDPOINTS; if (n) { computePointerWithAlignment(mem, mPzsOffsets, n); } @@ -65,7 +65,7 @@ void* GPUTPCClusterFinder::SetPointersZSOffset(void* mem) void* GPUTPCClusterFinder::SetPointersZS(void* mem) { - if (mNMaxPages && (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding)) { + if (mNMaxPages && (mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCClusterFinding)) { computePointerWithAlignment(mem, mPzs, mNMaxPages * TPCZSHDR::TPC_ZS_PAGE_SIZE); } return mem; @@ -92,7 +92,7 @@ void* GPUTPCClusterFinder::SetPointersScratch(void* mem) computePointerWithAlignment(mem, mPchargeMap, TPCMapMemoryLayout::items(mRec->GetProcessingSettings().overrideClusterizerFragmentLen)); computePointerWithAlignment(mem, mPpeakMap, TPCMapMemoryLayout::items(mRec->GetProcessingSettings().overrideClusterizerFragmentLen)); computePointerWithAlignment(mem, mPclusterByRow, GPUCA_ROW_COUNT * mNMaxClusterPerRow); - if ((mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding)) { + if ((mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCClusterFinding)) { computePointerWithAlignment(mem, mPscanBuf, mBufSize * mNBufs); } return mem; @@ -131,15 +131,15 @@ void GPUTPCClusterFinder::SetMaxData(const GPUTrackingInOutPointers& io) if (mRec->GetProcessingSettings().tpcIncreasedMinClustersPerRow) { mNMaxClusterPerRow = std::max(mNMaxClusterPerRow, mRec->GetProcessingSettings().tpcIncreasedMinClustersPerRow); } - if ((mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding)) { - mBufSize = nextMultipleOf(mNMaxDigitsFragment, std::max(GPUCA_MEMALIGN, mRec->getGPUParameters(mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding).par_CF_SCAN_WORKGROUP_SIZE)); + if ((mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCClusterFinding)) { + mBufSize = nextMultipleOf(mNMaxDigitsFragment, std::max(GPUCA_MEMALIGN, mRec->getGPUParameters(mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCClusterFinding).par_CF_SCAN_WORKGROUP_SIZE)); mNBufs = getNSteps(mBufSize); } } void GPUTPCClusterFinder::SetNMaxDigits(size_t nDigits, size_t nPages, size_t nDigitsFragment, size_t nDigitsEndpointMax) { - mNMaxDigits = nextMultipleOf(nDigits, std::max(GPUCA_MEMALIGN, mRec->getGPUParameters(mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding).par_CF_SCAN_WORKGROUP_SIZE)); + mNMaxDigits = nextMultipleOf(nDigits, std::max(GPUCA_MEMALIGN, mRec->getGPUParameters(mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCClusterFinding).par_CF_SCAN_WORKGROUP_SIZE)); mNMaxPages = nPages; mNMaxDigitsFragment = nDigitsFragment; mNMaxDigitsEndpoint = nDigitsEndpointMax; @@ -151,7 +151,7 @@ uint32_t GPUTPCClusterFinder::getNSteps(size_t items) const return 0; } uint32_t c = 1; - const size_t scanWorkgroupSize = mRec->getGPUParameters(mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding).par_CF_SCAN_WORKGROUP_SIZE; + const size_t scanWorkgroupSize = mRec->getGPUParameters(mRec->GetRecoStepsGPU() & gpudatatypes::RecoStep::TPCClusterFinding).par_CF_SCAN_WORKGROUP_SIZE; size_t capacity = scanWorkgroupSize; while (items > capacity) { capacity *= scanWorkgroupSize; diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.h index 35e2a7297338f..6958134d7d716 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.h @@ -17,7 +17,7 @@ #include "GPUDef.h" #include "GPUProcessor.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include "CfFragment.h" namespace o2 diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCNNClusterizerKernels.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCNNClusterizerKernels.h index 9353722568b1f..c77a99bec3a70 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCNNClusterizerKernels.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCNNClusterizerKernels.h @@ -44,9 +44,9 @@ class GPUTPCNNClusterizerKernels : public GPUKernelTemplate uint8_t innerAboveThreshold[SCRATCH_PAD_WORK_GROUP_SIZE]; }; - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { - return GPUDataTypes::RecoStep::TPCClusterFinding; + return gpudatatypes::RecoStep::TPCClusterFinding; } enum K : int32_t { diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTrackerKernels.h b/GPU/GPUTracking/TRDTracking/GPUTRDTrackerKernels.h index 21135ddc48dfa..f9d500a72597a 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTrackerKernels.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTrackerKernels.h @@ -26,7 +26,7 @@ class GPUTRDTrackerKernels : public GPUKernelTemplate enum K { defaultKernel = 0, gpuVersion = 0, o2Version = 1 }; - GPUhdi() constexpr static GPUDataTypes::RecoStep GetRecoStep() { return GPUDataTypes::RecoStep::TRDTracking; } + GPUhdi() constexpr static gpudatatypes::RecoStep GetRecoStep() { return gpudatatypes::RecoStep::TRDTracking; } template GPUd() static void Thread(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUsharedref() GPUSharedMemory& smem, processorType& processors, T* externalInstance = nullptr); }; diff --git a/GPU/GPUTracking/TRDTracking/macros/run_trd_tracker.C b/GPU/GPUTracking/TRDTracking/macros/run_trd_tracker.C index 3d86a77b6d9cc..acfcf92370b00 100644 --- a/GPU/GPUTracking/TRDTracking/macros/run_trd_tracker.C +++ b/GPU/GPUTracking/TRDTracking/macros/run_trd_tracker.C @@ -17,7 +17,7 @@ #include "GPUReconstruction.h" #include "GPUChainTracking.h" #include "GPUSettings.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include "GPUTRDDef.h" #include "GPUTRDTrack.h" #include "GPUTRDTracker.h" @@ -70,7 +70,7 @@ void run_trd_tracker(std::string path = "./", GPUSettingsProcessing cfgDeviceProcessing; // also keep defaults here, or adjust debug level cfgDeviceProcessing.debugLevel = 5; GPURecoStepConfiguration cfgRecoStep; - cfgRecoStep.steps = GPUDataTypes::RecoStep::NoRecoStep; + cfgRecoStep.steps = gpudatatypes::RecoStep::NoRecoStep; cfgRecoStep.inputs.clear(); cfgRecoStep.outputs.clear(); auto rec = GPUReconstruction::CreateInstance("CPU", true); diff --git a/GPU/GPUTracking/dEdx/GPUdEdx.h b/GPU/GPUTracking/dEdx/GPUdEdx.h index 758c2a7eabfca..e64e2b37945c8 100644 --- a/GPU/GPUTracking/dEdx/GPUdEdx.h +++ b/GPU/GPUTracking/dEdx/GPUdEdx.h @@ -23,6 +23,7 @@ #include "CalibdEdxContainer.h" #include "GPUTPCGeometry.h" #include "GPUDebugStreamer.h" +#include "GPUDataTypesIO.h" namespace o2::gpu { diff --git a/GPU/GPUTracking/display/GPUDisplay.h b/GPU/GPUTracking/display/GPUDisplay.h index 837995ef38bb4..b0c1c1d11f2cf 100644 --- a/GPU/GPUTracking/display/GPUDisplay.h +++ b/GPU/GPUTracking/display/GPUDisplay.h @@ -37,6 +37,7 @@ class GPUTPCTracker; struct GPUParam; class GPUQA; class GPUTRDGeometry; +class GPUTPCGMPropagator; class GPUDisplay : public GPUDisplayInterface { diff --git a/GPU/GPUTracking/display/render/GPUDisplayDraw.cxx b/GPU/GPUTracking/display/render/GPUDisplayDraw.cxx index 4953815a6fc19..6447d30daefe3 100644 --- a/GPU/GPUTracking/display/render/GPUDisplayDraw.cxx +++ b/GPU/GPUTracking/display/render/GPUDisplayDraw.cxx @@ -817,7 +817,7 @@ size_t GPUDisplay::DrawGLScene_updateVertexList() int32_t numThreads = getNumThreads(); tbb::task_arena(numThreads).execute([&] { - if (mChain && (mChain->GetRecoSteps() & GPUDataTypes::RecoStep::TPCSectorTracking)) { + if (mChain && (mChain->GetRecoSteps() & gpudatatypes::RecoStep::TPCSectorTracking)) { tbb::parallel_for(0, NSECTORS, [&](int32_t iSector) { GPUTPCTracker& tracker = (GPUTPCTracker&)sectorTracker(iSector); tracker.SetPointersDataLinks(tracker.LinkTmpMemory()); @@ -964,7 +964,6 @@ size_t GPUDisplay::DrawGLScene_updateVertexList() if (timer.IsRunning()) { GPUInfo("Display Time: Vertex Clusters:\t\t\t%6.0f us", timer.GetCurrentElapsedTime(true) * 1e6); } - }); // End omp parallel diff --git a/GPU/GPUTracking/qa/GPUQA.h b/GPU/GPUTracking/qa/GPUQA.h index 3dd49e2ec1373..346c56a898806 100644 --- a/GPU/GPUTracking/qa/GPUQA.h +++ b/GPU/GPUTracking/qa/GPUQA.h @@ -16,6 +16,7 @@ #define GPUQA_H #include "GPUSettings.h" +#include "GPUDataTypesQA.h" struct AliHLTTPCClusterMCWeight; class TH1F; class TH2F; @@ -56,16 +57,13 @@ class GPUQA static bool QAAvailable() { return false; } static bool IsInitialized() { return false; } void UpdateChain(GPUChainTracking* chain) {} - - enum QA_TASKS { - tasksAutomatic = 0 - }; }; } // namespace o2::gpu #else #include "GPUTPCDef.h" +#include "GPUDataTypesIO.h" #include #include #include @@ -150,21 +148,7 @@ class GPUQA static constexpr int32_t MC_LABEL_INVALID = -1e9; - enum QA_TASKS { // TODO: make this in32_t typed - taskTrackingEff = 1, - taskTrackingRes = 2, - taskTrackingResPull = 4, - tasksAllMC = 8 - 1, - taskClusterAttach = 8, - taskTrackStatistics = 16, - taskClusterCounts = 32, - taskClusterRejection = 64, - tasksAll = 128 - 1, - tasksDefault = tasksAll, - tasksDefaultPostprocess = tasksDefault & ~taskClusterCounts, - tasksAllNoQC = tasksAll & ~tasksAllMC, - tasksAutomatic = -1 - }; + using enum gpudatatypes::gpuqa::gpuQATaskIds; private: struct additionalMCParameters { diff --git a/GPU/Workflow/helper/include/GPUWorkflowHelper/GPUWorkflowHelper.h b/GPU/Workflow/helper/include/GPUWorkflowHelper/GPUWorkflowHelper.h index 225b6f75b1511..2802811b2e02b 100644 --- a/GPU/Workflow/helper/include/GPUWorkflowHelper/GPUWorkflowHelper.h +++ b/GPU/Workflow/helper/include/GPUWorkflowHelper/GPUWorkflowHelper.h @@ -14,7 +14,7 @@ #include "ReconstructionDataFormats/GlobalTrackID.h" #include "DataFormatsGlobalTracking/RecoContainer.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include namespace o2::gpu diff --git a/GPU/Workflow/src/GPUWorkflowInternal.h b/GPU/Workflow/src/GPUWorkflowInternal.h index 73d3676f3d84a..1ad6f3df13f5a 100644 --- a/GPU/Workflow/src/GPUWorkflowInternal.h +++ b/GPU/Workflow/src/GPUWorkflowInternal.h @@ -15,7 +15,7 @@ #ifndef O2_GPU_GPUWORKFLOWINTERNAL_H #define O2_GPU_GPUWORKFLOWINTERNAL_H -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include #include #include diff --git a/GPU/Workflow/src/GPUWorkflowPipeline.cxx b/GPU/Workflow/src/GPUWorkflowPipeline.cxx index ba395cd98d64d..f0aeb8089e27a 100644 --- a/GPU/Workflow/src/GPUWorkflowPipeline.cxx +++ b/GPU/Workflow/src/GPUWorkflowPipeline.cxx @@ -15,7 +15,7 @@ #include "GPUWorkflow/GPUWorkflowSpec.h" #include "GPUO2InterfaceConfiguration.h" #include "GPUO2Interface.h" -#include "GPUDataTypes.h" +#include "GPUDataTypesIO.h" #include "GPUSettings.h" #include "GPUWorkflowInternal.h" diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index ca929bb025f80..6011cc3dc3e9f 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -79,6 +79,7 @@ #include "DetectorsRaw/RDHUtils.h" #include "ITStracking/TrackingInterface.h" #include "GPUWorkflowInternal.h" +#include "GPUDataTypesQA.h" // #include "Framework/ThreadPool.h" #include @@ -180,7 +181,7 @@ void GPURecoWorkflowSpec::init(InitContext& ic) mConfig->configQA.shipToQC = true; if (!mConfig->configProcessing.runQA) { mConfig->configQA.enableLocalOutput = false; - mQATaskMask = (mSpecConfig.processMC ? 15 : 0) | (mConfig->configQA.clusterRejectionHistograms ? 32 : 0); // TODO: Clean up using numeric flags! + mQATaskMask = (mSpecConfig.processMC ? gpudatatypes::gpuqa::tasksAllMC : gpudatatypes::gpuqa::tasksNone) | (mConfig->configQA.clusterRejectionHistograms ? gpudatatypes::gpuqa::taskClusterCounts : gpudatatypes::gpuqa::tasksNone); mConfig->configProcessing.runQA = -mQATaskMask; } } @@ -190,39 +191,39 @@ void GPURecoWorkflowSpec::init(InitContext& ic) // Configure the "GPU workflow" i.e. which steps we run on the GPU (or CPU) if (runTracking) { - mConfig->configWorkflow.steps.set(GPUDataTypes::RecoStep::TPCConversion, - GPUDataTypes::RecoStep::TPCSectorTracking, - GPUDataTypes::RecoStep::TPCMerging); - mConfig->configWorkflow.outputs.set(GPUDataTypes::InOutType::TPCMergedTracks); + mConfig->configWorkflow.steps.set(gpudatatypes::RecoStep::TPCConversion, + gpudatatypes::RecoStep::TPCSectorTracking, + gpudatatypes::RecoStep::TPCMerging); + mConfig->configWorkflow.outputs.set(gpudatatypes::InOutType::TPCMergedTracks); } if (mSpecConfig.outputCompClustersRoot || mSpecConfig.outputCompClustersFlat) { - mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCCompression, true); - mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, true); + mConfig->configWorkflow.steps.setBits(gpudatatypes::RecoStep::TPCCompression, true); + mConfig->configWorkflow.outputs.setBits(gpudatatypes::InOutType::TPCCompressedClusters, true); } - mConfig->configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCClusters); + mConfig->configWorkflow.inputs.set(gpudatatypes::InOutType::TPCClusters); if (mSpecConfig.caClusterer) { // Override some settings if we have raw data as input - mConfig->configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCRaw); - mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCClusterFinding, true); - mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCClusters, true); + mConfig->configWorkflow.inputs.set(gpudatatypes::InOutType::TPCRaw); + mConfig->configWorkflow.steps.setBits(gpudatatypes::RecoStep::TPCClusterFinding, true); + mConfig->configWorkflow.outputs.setBits(gpudatatypes::InOutType::TPCClusters, true); } if (mSpecConfig.decompressTPC) { - mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCCompression, false); - mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TPCDecompression, true); - mConfig->configWorkflow.inputs.set(GPUDataTypes::InOutType::TPCCompressedClusters); - mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCClusters, true); - mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::TPCCompressedClusters, false); + mConfig->configWorkflow.steps.setBits(gpudatatypes::RecoStep::TPCCompression, false); + mConfig->configWorkflow.steps.setBits(gpudatatypes::RecoStep::TPCDecompression, true); + mConfig->configWorkflow.inputs.set(gpudatatypes::InOutType::TPCCompressedClusters); + mConfig->configWorkflow.outputs.setBits(gpudatatypes::InOutType::TPCClusters, true); + mConfig->configWorkflow.outputs.setBits(gpudatatypes::InOutType::TPCCompressedClusters, false); if (mTPCSectorMask != 0xFFFFFFFFF) { throw std::invalid_argument("Cannot run TPC decompression with a sector mask"); } } if (mSpecConfig.runTRDTracking) { - mConfig->configWorkflow.inputs.setBits(GPUDataTypes::InOutType::TRDTracklets, true); - mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::TRDTracking, true); + mConfig->configWorkflow.inputs.setBits(gpudatatypes::InOutType::TRDTracklets, true); + mConfig->configWorkflow.steps.setBits(gpudatatypes::RecoStep::TRDTracking, true); } if (mSpecConfig.runITSTracking) { - mConfig->configWorkflow.inputs.setBits(GPUDataTypes::InOutType::ITSClusters, true); - mConfig->configWorkflow.outputs.setBits(GPUDataTypes::InOutType::ITSTracks, true); - mConfig->configWorkflow.steps.setBits(GPUDataTypes::RecoStep::ITSTracking, true); + mConfig->configWorkflow.inputs.setBits(gpudatatypes::InOutType::ITSClusters, true); + mConfig->configWorkflow.outputs.setBits(gpudatatypes::InOutType::ITSTracks, true); + mConfig->configWorkflow.steps.setBits(gpudatatypes::RecoStep::ITSTracking, true); } if (mSpecConfig.outputSharedClusterMap) { mConfig->configProcessing.outputSharedClusterMap = true; @@ -935,7 +936,7 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) } } - if (mConfig->configWorkflow.outputs.isSet(GPUDataTypes::InOutType::TPCMergedTracks)) { + if (mConfig->configWorkflow.outputs.isSet(gpudatatypes::InOutType::TPCMergedTracks)) { LOG(info) << "found " << ptrs.nOutputTracksTPCO2 << " track(s)"; } diff --git a/doc/data/2021-01-o2_prs.json b/doc/data/2021-01-o2_prs.json index 06cd97dd6d7b7..4ccf435f6086a 100644 --- a/doc/data/2021-01-o2_prs.json +++ b/doc/data/2021-01-o2_prs.json @@ -895,7 +895,7 @@ }, { "node": { - "path": "GPU/GPUTracking/Base/GPUDataTypes.h" + "path": "GPU/GPUTracking/Base/GPUDataTypesIO.h" } }, { @@ -2445,7 +2445,7 @@ }, { "node": { - "path": "GPU/GPUTracking/DataTypes/GPUDataTypes.h" + "path": "GPU/GPUTracking/DataTypes/GPUDataTypesIO.h" } }, { From 670518f435ac5c22c532fbd5d4d696873d8d2db7 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 14 Dec 2025 09:43:01 +0100 Subject: [PATCH 014/234] Upgrades ECal: Fix codechecker violation --- Detectors/Upgrades/ALICE3/ECal/DataFormatsECal/src/Cluster.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Detectors/Upgrades/ALICE3/ECal/DataFormatsECal/src/Cluster.cxx b/Detectors/Upgrades/ALICE3/ECal/DataFormatsECal/src/Cluster.cxx index 77f7d9219ef6b..f792344f1f50f 100644 --- a/Detectors/Upgrades/ALICE3/ECal/DataFormatsECal/src/Cluster.cxx +++ b/Detectors/Upgrades/ALICE3/ECal/DataFormatsECal/src/Cluster.cxx @@ -50,7 +50,8 @@ int Cluster::getMcTrackID() const TLorentzVector Cluster::getMomentum() const { double r = std::sqrt(mX * mX + mY * mY + mZ * mZ); - if (r == 0) + if (r == 0) { return TLorentzVector(); + } return TLorentzVector(mE * mX / r, mE * mY / r, mE * mZ / r, mE); } From 303fbca420a30dbab975740f576c8673480943a4 Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Sun, 14 Dec 2025 22:11:27 +0100 Subject: [PATCH 015/234] add previously list init function call --- Steer/src/CollisionContextTool.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/Steer/src/CollisionContextTool.cxx b/Steer/src/CollisionContextTool.cxx index b884909aedd9d..6bee407c01264 100644 --- a/Steer/src/CollisionContextTool.cxx +++ b/Steer/src/CollisionContextTool.cxx @@ -496,6 +496,7 @@ int main(int argc, char* argv[]) // this loop makes sure that the first collision is within the range of orbits asked (if noEmptyTF is enabled) do { sampler->setFirstIR(o2::InteractionRecord(options.firstBC, orbitstart)); + sampler->init(); record = sampler->generateCollisionTime(); } while (options.noEmptyTF && usetimeframelength && record.orbit >= orbitstart + orbits_total); int count = 0; From 92f73dd45a43ac26c4fe1f577b75e992b32a84ad Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Mon, 15 Dec 2025 11:29:58 +0100 Subject: [PATCH 016/234] DPL GUI: Fix activity display (#14916) --- .../src/FrameworkGUIDataRelayerUsage.cxx | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/Framework/GUISupport/src/FrameworkGUIDataRelayerUsage.cxx b/Framework/GUISupport/src/FrameworkGUIDataRelayerUsage.cxx index 1d3b4f24ea34c..86558d22b973d 100644 --- a/Framework/GUISupport/src/FrameworkGUIDataRelayerUsage.cxx +++ b/Framework/GUISupport/src/FrameworkGUIDataRelayerUsage.cxx @@ -43,7 +43,7 @@ struct HeatMapHelper { { float padding = 1; // add slider to scroll between the grid display windows - size_t nw = getNumRecords() / WND; + size_t nw = getNumRecords() < WND ? 1 : getNumRecords() / WND; ImGui::PushItemWidth(sizeHint.x); ImGui::SliderInt("##window", &v, 1, nw, "wnd: %d", ImGuiSliderFlags_AlwaysClamp); ImVec2 sliderMin = ImGui::GetItemRectMin(); @@ -51,7 +51,7 @@ struct HeatMapHelper { constexpr float MAX_BOX_X_SIZE = 16.f; constexpr float MAX_BOX_Y_SIZE = 16.f; - ImVec2 size = ImVec2(sizeHint.x, std::min(sizeHint.y, MAX_BOX_Y_SIZE * getNumItems(0) + 2)); + ImVec2 size = ImVec2(sizeHint.x, std::min(sizeHint.y, MAX_BOX_Y_SIZE * getNumInputs() + 2)); ImU32 BORDER_COLOR = ImColor(200, 200, 200, 255); ImU32 BACKGROUND_COLOR = ImColor(20, 20, 20, 255); ImU32 BORDER_COLOR_A = ImColor(200, 200, 200, 0); @@ -75,19 +75,22 @@ struct HeatMapHelper { const static auto colorE = ImColor(ImVec4{0, 0, 0, 0}); drawList->PrimReserve(nw * 6, nw * 4); - for (size_t iw = 0; iw < nw; ++iw) { - ImVec2 xOffset{iw * xsz + 2 * padding, 0}; + for (size_t iw = 1; iw <= nw; ++iw) { + ImVec2 xOffset{(iw - 1) * xsz + 2 * padding, 0}; ImVec2 xSize{xsz - 2 * padding, 0}; ImVec2 yOffset{0, 2 * padding}; - ImVec2 ySize{0, 16 - 4 * padding}; - bool active = 0; - for (size_t ir = iw; ir < ((iw + WND > getNumRecords()) ? getNumRecords() : iw + WND); ++ir) { - for (size_t i = 0; i < getNumItems(ir); ++i) { - active = getValue(*getItem(ir, i)) > 0; + ImVec2 ySize{0, MAX_BOX_Y_SIZE - 4 * padding}; + bool active = false; + for (size_t ir = (iw - 1) * WND; ir < ((iw * WND > getNumRecords()) ? getNumRecords() : iw * WND); ++ir) { + for (size_t i = 0; i < getNumItems(getRecord(ir)); ++i) { + active = getValue(*getItem(getRecord(ir), i)) > 0; if (active) { break; } } + if (active) { + break; + } } drawList->PrimRect( xOffset + yOffset + winPos, @@ -96,47 +99,46 @@ struct HeatMapHelper { } // display the grid - size_t recordsWindow = v * WND; auto boxSizeX = std::min(size.x / WND, MAX_BOX_X_SIZE); - auto numInputs = getNumInputs(); + auto boxSizeY = std::min(size.y / getNumInputs(), MAX_BOX_Y_SIZE); + winPos = ImGui::GetCursorScreenPos() + ImVec2{0, 7}; - ImGui::InvisibleButton("sensible area", ImVec2(size.x, size.y)); + ImGui::InvisibleButton("sensitive area", ImVec2(size.x, size.y)); if (ImGui::IsItemHovered()) { auto pos = ImGui::GetMousePos() - winPos; - auto slot = (v - 1) * WND + std::lround(std::trunc(pos.x / size.x * WND)); - auto row = std::lround(std::trunc(pos.y / size.y * numInputs)); + auto slot = (v - 1) * WND + std::lround(std::trunc(pos.x / boxSizeX)); + auto row = std::lround(std::trunc(pos.y / boxSizeY)); describeCell(row, slot); } + // background drawList->AddRectFilled( ImVec2(0., 0.) + winPos, ImVec2{size.x, size.y} + winPos, BACKGROUND_COLOR); + // border drawList->AddRect( ImVec2(0. - 1, -1) + winPos, ImVec2{size.x + 1, size.y - 1} + winPos, BORDER_COLOR); - size_t totalRects = 0; - for (size_t ri = (v - 1) * WND; ri < recordsWindow; ri++) { - auto record = getRecord(ri); - totalRects += getNumItems(record); - } - - drawList->PrimReserve(totalRects * 6, totalRects * 4); - for (size_t ri = (v - 1) * WND; ri < recordsWindow; ri++) { + // heatmap + size_t totalPrims = WND * getNumInputs(); + drawList->PrimReserve(totalPrims * 6, totalPrims * 4); + for (size_t ri = (v - 1) * WND; ri < (((size_t)(v)*WND > getNumRecords()) ? getNumRecords() : v * WND); ++ri) { auto record = getRecord(ri); - ImVec2 xOffset{((ri - (v - 1) * WND) * boxSizeX) + padding, 0}; + ImVec2 xOffset{((float)(ri - (v - 1) * WND) * boxSizeX) + padding, 0}; ImVec2 xSize{boxSizeX - 2 * padding, 0}; - auto me = getNumItems(record); - auto boxSizeY = std::min(size.y / me, MAX_BOX_Y_SIZE); - for (size_t mi = 0; mi < me; mi++) { - ImVec2 yOffSet{0, (mi * boxSizeY) + padding}; + + for (auto mi = 0U; mi < getNumItems(record); mi++) { + ImVec2 yOffSet{0, ((float)mi * boxSizeY) + padding}; ImVec2 ySize{0, boxSizeY - 2 * padding}; + ImVec2 A = xOffset + yOffSet + winPos; + ImVec2 B = xOffset + xSize + yOffSet + ySize + winPos; + drawList->PrimRect( - xOffset + yOffSet + winPos, - xOffset + xSize + yOffSet + ySize + winPos, + A, B, getColor(getValue(*getItem(record, mi)))); } } From 4090041b401c7aa6c919ca923126fff950cbccd1 Mon Sep 17 00:00:00 2001 From: iravasen Date: Mon, 15 Dec 2025 19:41:39 +0100 Subject: [PATCH 017/234] ITS calib: change option name to avoid ambiguity (#14920) --- Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx index 0a08841059d63..ce0b840f4a037 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx @@ -74,7 +74,7 @@ void ITSThresholdCalibrator::init(InitContext& ic) LOG(warning) << "mColStep = " << mColStep << ": saving s-curves of only 1 pixel (pix 0) per row"; } - isLocal = ic.options().get("local"); + isLocal = ic.options().get("local-processing"); std::string fittype = ic.options().get("fittype"); if (fittype == "derivative") { @@ -2069,7 +2069,7 @@ DataProcessorSpec getITSThresholdCalibratorSpec(const ITSCalibInpConf& inpConf) {"meb-select", VariantType::Int, -1, {"Select from which multi-event buffer consider the hits: 0,1 or 2"}}, {"s-curve-col-step", VariantType::Int, 8, {"save s-curves points to tree every s-curve-col-step pixels on 1 row"}}, {"percentage-cut", VariantType::Int, 25, {"discard chip in ITHR/VCASN scan if the percentage of success is less than this cut"}}, - {"local", VariantType::Bool, false, {"Enable in case of data replay of scans processed row by row or in 1 go in finalize() but with partial data in the raw TF (e.g. data dump stopped before the real end of run)"}}}}; + {"local-processing", VariantType::Bool, false, {"Enable in case of data replay of scans processed row by row or in 1 go in finalize() but with partial data in the raw TF (e.g. data dump stopped before the real end of run)"}}}}; } } // namespace its } // namespace o2 From 2eba0da0195570e9987ee2a65ff5193ebdffbacd Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Tue, 11 Nov 2025 10:05:19 +0100 Subject: [PATCH 018/234] Common: add host symbols to RangeRef Signed-off-by: Felix Schlepper --- .../include/CommonDataFormat/RangeReference.h | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/DataFormats/common/include/CommonDataFormat/RangeReference.h b/DataFormats/common/include/CommonDataFormat/RangeReference.h index 0308d3b8af937..3d0c58298de03 100644 --- a/DataFormats/common/include/CommonDataFormat/RangeReference.h +++ b/DataFormats/common/include/CommonDataFormat/RangeReference.h @@ -29,23 +29,23 @@ template class RangeReference { public: - GPUd() RangeReference(FirstEntry ent, NElem n) { set(ent, n); } - GPUdDefault() RangeReference(const RangeReference& src) = default; - GPUdDefault() RangeReference() = default; - GPUdDefault() ~RangeReference() = default; - GPUd() void set(FirstEntry ent, NElem n) + GPUhd() RangeReference(FirstEntry ent, NElem n) { set(ent, n); } + GPUhdDefault() RangeReference(const RangeReference& src) = default; + GPUhdDefault() RangeReference() = default; + GPUhdDefault() ~RangeReference() = default; + GPUhd() void set(FirstEntry ent, NElem n) { mFirstEntry = ent; mEntries = n; } - GPUd() void clear() { set(0, 0); } - GPUd() FirstEntry getFirstEntry() const { return mFirstEntry; } - GPUd() FirstEntry getEntriesBound() const { return mFirstEntry + mEntries; } - GPUd() NElem getEntries() const { return mEntries; } - GPUd() void setFirstEntry(FirstEntry ent) { mFirstEntry = ent; } - GPUd() void setEntries(NElem n) { mEntries = n; } - GPUd() void changeEntriesBy(NElem inc) { mEntries += inc; } - GPUd() bool operator==(const RangeReference& other) const + GPUhd() void clear() { set(0, 0); } + GPUhd() FirstEntry getFirstEntry() const { return mFirstEntry; } + GPUhd() FirstEntry getEntriesBound() const { return mFirstEntry + mEntries; } + GPUhd() NElem getEntries() const { return mEntries; } + GPUhd() void setFirstEntry(FirstEntry ent) { mFirstEntry = ent; } + GPUhd() void setEntries(NElem n) { mEntries = n; } + GPUhd() void changeEntriesBy(NElem inc) { mEntries += inc; } + GPUhd() bool operator==(const RangeReference& other) const { return mFirstEntry == other.mFirstEntry && mEntries == other.mEntries; } @@ -68,21 +68,21 @@ class RangeRefComp static constexpr Base MaskN = ((0x1 << NBitsN) - 1); static constexpr Base MaskR = (~Base(0)) & (~MaskN); Base mData = 0; ///< packed 1st entry reference + N entries - GPUd() void sanityCheck() + GPUhd() void sanityCheck() { static_assert(NBitsN < NBitsTotal, "NBitsN too large"); } public: - GPUd() RangeRefComp(int ent, int n) { set(ent, n); } - GPUdDefault() RangeRefComp() = default; - GPUdDefault() RangeRefComp(const RangeRefComp& src) = default; + GPUhd() RangeRefComp(int ent, int n) { set(ent, n); } + GPUhdDefault() RangeRefComp() = default; + GPUhdDefault() RangeRefComp(const RangeRefComp& src) = default; GPUhd() void set(int ent, int n) { mData = (Base(ent) << NBitsN) + (Base(n) & MaskN); } - GPUd() static constexpr Base getMaxFirstEntry() { return MaskR >> NBitsN; } - GPUd() static constexpr Base getMaxEntries() { return MaskN; } + GPUhd() static constexpr Base getMaxFirstEntry() { return MaskR >> NBitsN; } + GPUhd() static constexpr Base getMaxEntries() { return MaskN; } GPUhd() int getFirstEntry() const { return mData >> NBitsN; } GPUhd() int getEntries() const { return mData & ((0x1 << NBitsN) - 1); } GPUhd() int getEntriesBound() const { return getFirstEntry() + getEntries(); } From 33a68caa22edc089ec63ccb92a15890d5b3871b2 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Fri, 7 Nov 2025 10:37:22 +0100 Subject: [PATCH 019/234] Common: new linkdef for TimeStamp Signed-off-by: Felix Schlepper --- DataFormats/common/src/CommonDataFormatLinkDef.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DataFormats/common/src/CommonDataFormatLinkDef.h b/DataFormats/common/src/CommonDataFormatLinkDef.h index 631305cd28f13..d66e89af637cc 100644 --- a/DataFormats/common/src/CommonDataFormatLinkDef.h +++ b/DataFormats/common/src/CommonDataFormatLinkDef.h @@ -26,10 +26,12 @@ #pragma link C++ class o2::dataformats::TimeStamp < float> + ; #pragma link C++ class o2::dataformats::TimeStamp < double> + ; #pragma link C++ class o2::dataformats::TimeStamp < int> + ; -#pragma link C++ class o2::dataformats::TimeStamp < Float16_t > + ; +#pragma link C++ class o2::dataformats::TimeStamp < uint32_t> + ; +#pragma link C++ class o2::dataformats::TimeStamp < Float16_t> + ; #pragma link C++ class o2::dataformats::TimeStampWithError < float, float> + ; #pragma link C++ class o2::dataformats::TimeStampWithError < double, double> + ; #pragma link C++ class o2::dataformats::TimeStampWithError < int, int> + ; +#pragma link C++ class o2::dataformats::TimeStampWithError < uint32_t, uint16_t> + ; #pragma link C++ class o2::dataformats::EvIndex < int, int> + ; #pragma link C++ class o2::dataformats::RangeReference < int, int> + ; From 73948550572a8c1a1280290b15043b9aef17a50e Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Tue, 25 Nov 2025 14:52:37 +0100 Subject: [PATCH 020/234] Reco: Add cov setters for ind. elements --- .../ReconstructionDataFormats/Vertex.h | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h index 2d13e029f8c00..cb1c9d5d87c7f 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/Vertex.h @@ -45,9 +45,17 @@ class VertexBase static constexpr int kNCov = 6; GPUhdDefault() VertexBase() = default; GPUhdDefault() ~VertexBase() = default; - GPUhd() VertexBase(const math_utils::Point3D& pos, const std::array& cov) : mPos(pos), mCov(cov) + GPUhd() VertexBase(const float* pos, const float* cov) { + mPos = math_utils::Point3D(pos[0], pos[1], pos[2]); + mCov[kCovXX] = cov[kCovXX]; + mCov[kCovXY] = cov[kCovXY]; + mCov[kCovXZ] = cov[kCovXZ]; + mCov[kCovYY] = cov[kCovYY]; + mCov[kCovYZ] = cov[kCovYZ]; + mCov[kCovZZ] = cov[kCovZZ]; } + GPUhd() VertexBase(const math_utils::Point3D& pos, const std::array& cov) : mPos(pos), mCov(cov) {} #if !defined(GPUCA_NO_FMT) && !defined(GPUCA_GPUCODE_DEVICE) void print() const; @@ -58,6 +66,7 @@ class VertexBase GPUhd() float getX() const { return mPos.X(); } GPUhd() float getY() const { return mPos.Y(); } GPUhd() float getZ() const { return mPos.Z(); } + GPUhd() float getR() const { return gpu::CAMath::Hypot(mPos.X(), mPos.Y()); } GPUd() float getSigmaX2() const { return mCov[kCovXX]; } GPUd() float getSigmaY2() const { return mCov[kCovYY]; } GPUd() float getSigmaZ2() const { return mCov[kCovZZ]; } @@ -69,6 +78,7 @@ class VertexBase GPUd() float getSigmaZ() const { return gpu::CAMath::Sqrt(getSigmaZ2()); } GPUd() const std::array& getCov() const { return mCov; } + GPUd() float getCov(int e) const { return mCov[e]; } GPUd() math_utils::Point3D getXYZ() const { return mPos; } GPUd() math_utils::Point3D& getXYZ() { return mPos; } @@ -105,6 +115,7 @@ class VertexBase setSigmaYZ(syz); } GPUd() void setCov(const std::array& cov) { mCov = cov; } + GPUd() void setCov(float c, int e) { mCov[e] = c; } bool operator==(const VertexBase& other) const; bool operator!=(const VertexBase& other) const { return !(*this == other); } @@ -133,10 +144,8 @@ class Vertex : public VertexBase GPUhdDefault() Vertex() = default; GPUhdDefault() ~Vertex() = default; - GPUhd() Vertex(const math_utils::Point3D& pos, const std::array& cov, ushort nCont, float chi2) - : VertexBase(pos, cov), mChi2(chi2), mNContributors(nCont) - { - } + GPUhd() Vertex(const float* pos, const float* cov, ushort nCont, float chi2) : VertexBase(pos, cov), mChi2(chi2), mNContributors(nCont) {} + GPUhd() Vertex(const math_utils::Point3D& pos, const std::array& cov, ushort nCont, float chi2) : VertexBase(pos, cov), mChi2(chi2), mNContributors(nCont) {} #if !defined(GPUCA_NO_FMT) && !defined(GPUCA_GPUCODE_DEVICE) void print() const; From 0244a9838fd7dfff28a8fbff1fa0597af6a6234f Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Tue, 16 Dec 2025 11:37:27 +0100 Subject: [PATCH 021/234] ITSMFT&ITS3&TRK: load response functions from ccdb (#14902) * ITSMFT&ITS3: load response functions from ccdb Signed-off-by: Felix Schlepper * TRK: load response function from ccdb Signed-off-by: Felix Schlepper --------- Signed-off-by: Felix Schlepper --- .../data/AlpideResponseData/CMakeLists.txt | 25 -------- .../include/ITSMFTSimulation/Digitizer.h | 10 ++-- .../common/simulation/src/Digitizer.cxx | 30 ++-------- .../include/TRKSimulation/DigiParams.h | 11 ++-- .../include/TRKSimulation/Digitizer.h | 12 ++-- .../ALICE3/TRK/simulation/src/DigiParams.cxx | 13 +++- .../ALICE3/TRK/simulation/src/Digitizer.cxx | 10 +--- .../TRK/simulation/src/TRKSimulationLinkDef.h | 1 + Detectors/Upgrades/ITS3/CMakeLists.txt | 1 - Detectors/Upgrades/ITS3/data/CMakeLists.txt | 34 ----------- .../include/ITS3Simulation/DigiParams.h | 9 +-- .../include/ITS3Simulation/Digitizer.h | 20 +++---- .../ITS3/simulation/src/DigiParams.cxx | 10 ++-- .../ITS3/simulation/src/Digitizer.cxx | 59 +++++-------------- .../src/ITS3DigitizerSpec.cxx | 15 +++++ .../src/ITSMFTDigitizerSpec.cxx | 14 +++++ .../src/TRKDigitizerSpec.cxx | 6 ++ 17 files changed, 106 insertions(+), 174 deletions(-) delete mode 100644 Detectors/Upgrades/ITS3/data/CMakeLists.txt diff --git a/Detectors/ITSMFT/common/data/AlpideResponseData/CMakeLists.txt b/Detectors/ITSMFT/common/data/AlpideResponseData/CMakeLists.txt index d1f3e756394b1..f985857afa88c 100644 --- a/Detectors/ITSMFT/common/data/AlpideResponseData/CMakeLists.txt +++ b/Detectors/ITSMFT/common/data/AlpideResponseData/CMakeLists.txt @@ -9,33 +9,8 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. - o2_add_executable(alpide-response-generator SOURCES AlpideResponse.cxx PUBLIC_LINK_LIBRARIES O2::ITSMFTSimulation ROOT::Core TARGETVARNAME targetName) - -set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/Detectors/ITSMFT/common/data/AlpideResponseData/AlpideResponse.cxx) - -if(ITSRESPONSE) - message(STATUS "ITSRESPONSE option provided, setting ITSRESPONSE_DIR from it: " ${ITSRESPONSE}) - set(ITSRESPONSE_DIR ${ITSRESPONSE} CACHE PATH "ITSResponse directory") -else() - message(STATUS "ITSRESPONSE option not provided, setting ITSRESPONSE_DIR from environment ITSRESPONSE_ROOT: " $ENV{ITSRESPONSE_ROOT}) - set(ITSRESPONSE_DIR $ENV{ITSRESPONSE_ROOT} CACHE PATH "ITSResponse directory") -endif() - -add_custom_command(TARGET O2exe-alpide-response-generator POST_BUILD - COMMAND ${CMAKE_BINARY_DIR}/stage/bin/o2-alpide-response-generator -i ${ITSRESPONSE_DIR}/response/AlpideResponseData/ -o ${CMAKE_CURRENT_BINARY_DIR}/ - BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/AlpideResponseData.root - COMMENT "Generating AlpideResponseData.root" -) - -# # Add a target that depends on the custom command output -add_custom_target( - GenerateAlpideResponse ALL - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/AlpideResponseData.root -) - -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/AlpideResponseData.root" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/Detectors/ITSMFT/data/AlpideResponseData/") diff --git a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Digitizer.h b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Digitizer.h index e3995068c52cf..670dd32bf9f46 100644 --- a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Digitizer.h +++ b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Digitizer.h @@ -62,6 +62,7 @@ class Digitizer : public TObject void setDeadChannelsMap(const o2::itsmft::NoiseMap* mp) { mDeadChanMap = mp; } void init(); + void setAlpideResponse(const o2::itsmft::AlpideSimResponse* resp, int i) { mAlpSimResp[i] = resp; } auto getChipResponse(int chipID); @@ -124,11 +125,10 @@ class Digitizer : public TObject uint32_t mEventROFrameMax = 0; ///< highest RO frame forfor processed events (w/o automatic noise ROFs) int mNumberOfChips = 0; - o2::itsmft::AlpideSimResponse* mAlpSimRespMFT = nullptr; - o2::itsmft::AlpideSimResponse* mAlpSimRespIB = nullptr; - o2::itsmft::AlpideSimResponse* mAlpSimRespOB = nullptr; - o2::itsmft::AlpideSimResponse mAlpSimResp[2]; // simulated response - std::string mResponseFile = "$(O2_ROOT)/share/Detectors/ITSMFT/data/AlpideResponseData/AlpideResponseData.root"; + const o2::itsmft::AlpideSimResponse* mAlpSimRespMFT = nullptr; + const o2::itsmft::AlpideSimResponse* mAlpSimRespIB = nullptr; + const o2::itsmft::AlpideSimResponse* mAlpSimRespOB = nullptr; + const o2::itsmft::AlpideSimResponse* mAlpSimResp[2]; // simulated response const o2::itsmft::GeometryTGeo* mGeometry = nullptr; ///< ITS OR MFT upgrade geometry std::vector mChips; ///< Array of chips digits containers diff --git a/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx b/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx index e5dd35e6a084d..53e0a2fcb096f 100644 --- a/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx +++ b/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx @@ -48,24 +48,6 @@ void Digitizer::init() mChips[i].setDeadChanMap(mDeadChanMap); } } - // initializing for both collection tables - /*for (int i = 0; i < 2; i++) { - mAlpSimResp[i].initData(i); - }*/ - - // importing the charge collection tables - // (initialized while building O2) - auto file = TFile::Open(mResponseFile.data()); - if (!file) { - LOG(fatal) << "Cannot open response file " << mResponseFile; - } - /*std::string response = "response"; - for (int i=0; i<2; i++) { - response.append(std::to_string(i)); - mAlpSimResp[i] = *(o2::itsmft::AlpideSimResponse*)file->Get(response.data()); - }*/ - mAlpSimResp[0] = *(o2::itsmft::AlpideSimResponse*)file->Get("response0"); - mAlpSimResp[1] = *(o2::itsmft::AlpideSimResponse*)file->Get("response1"); // importing the parameters from DPLDigitizerParam.h auto& doptMFT = DPLDigitizerParam::Instance(); @@ -73,29 +55,29 @@ void Digitizer::init() // initializing response according to detector and back-bias value if (doptMFT.Vbb == 0.0) { // for MFT - mAlpSimRespMFT = mAlpSimResp; + mAlpSimRespMFT = mAlpSimResp[0]; LOG(info) << "Choosing Vbb=0V for MFT"; } else if (doptMFT.Vbb == 3.0) { - mAlpSimRespMFT = mAlpSimResp + 1; + mAlpSimRespMFT = mAlpSimResp[1]; LOG(info) << "Choosing Vbb=-3V for MFT"; } else { LOG(fatal) << "Invalid MFT back-bias value"; } if (doptITS.IBVbb == 0.0) { // for ITS Inner Barrel - mAlpSimRespIB = mAlpSimResp; + mAlpSimRespIB = mAlpSimResp[0]; LOG(info) << "Choosing Vbb=0V for ITS IB"; } else if (doptITS.IBVbb == 3.0) { - mAlpSimRespIB = mAlpSimResp + 1; + mAlpSimRespIB = mAlpSimResp[1]; LOG(info) << "Choosing Vbb=-3V for ITS IB"; } else { LOG(fatal) << "Invalid ITS Inner Barrel back-bias value"; } if (doptITS.OBVbb == 0.0) { // for ITS Outter Barrel - mAlpSimRespOB = mAlpSimResp; + mAlpSimRespOB = mAlpSimResp[0]; LOG(info) << "Choosing Vbb=0V for ITS OB"; } else if (doptITS.OBVbb == 3.0) { - mAlpSimRespOB = mAlpSimResp + 1; + mAlpSimRespOB = mAlpSimResp[1]; LOG(info) << "Choosing Vbb=-3V for ITS OB"; } else { LOG(fatal) << "Invalid ITS Outter Barrel back-bias value"; diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/DigiParams.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/DigiParams.h index 970b20c48816e..0463a68a77c3e 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/DigiParams.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/DigiParams.h @@ -16,7 +16,8 @@ #define ALICEO2_TRK_DIGIPARAMS_H #include -#include +#include "ITSMFTSimulation/AlpideSignalTrapezoid.h" +#include "ITSMFTSimulation/AlpideSimResponse.h" #include "TRKBase/TRKBaseParam.h" #include "TRKBase/GeometryTGeo.h" @@ -91,8 +92,8 @@ class DigiParams bool isTimeOffsetSet() const { return mTimeOffset > -infTime; } - const o2::trk::ChipSimResponse* getAlpSimResponse() const { return mAlpSimResponse; } - void setAlpSimResponse(const o2::trk::ChipSimResponse* par) { mAlpSimResponse = par; } + const o2::trk::ChipSimResponse* getAlpSimResponse() const { return mAlpSimResponse.get(); } + void setAlpSimResponse(const o2::itsmft::AlpideSimResponse*); const SignalShape& getSignalShape() const { return mSignalShape; } SignalShape& getSignalShape() { return (SignalShape&)mSignalShape; } @@ -122,7 +123,7 @@ class DigiParams o2::itsmft::AlpideSignalTrapezoid mSignalShape; ///< signal timeshape parameterization - const o2::trk::ChipSimResponse* mAlpSimResponse = nullptr; //!< pointer on external response + std::unique_ptr mAlpSimResponse; //!< pointer on external response // auxiliary precalculated parameters float mROFrameLengthInv = 0; ///< inverse length of RO frame in ns @@ -132,4 +133,4 @@ class DigiParams } // namespace trk } // namespace o2 -#endif \ No newline at end of file +#endif diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Digitizer.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Digitizer.h index 8e7173af8b820..221d7b342bf59 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Digitizer.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Digitizer.h @@ -51,7 +51,7 @@ class Digitizer void init(); - o2::trk::ChipSimResponse* getChipResponse(int chipID); + const o2::trk::ChipSimResponse* getChipResponse(int chipID); /// Steer conversion of hits to digits void process(const std::vector* hits, int evID, int srcID); @@ -66,7 +66,6 @@ class Digitizer bool isContinuous() const { return mParams.isContinuous(); } void fillOutputContainer(uint32_t maxFrame = 0xffffffff); - void setDigiParams(const o2::trk::DigiParams& par) { mParams = par; } const o2::trk::DigiParams& getDigitParams() const { return mParams; } // provide the common trk::GeometryTGeo to access matrices and segmentation @@ -142,12 +141,9 @@ class Digitizer int mNumberOfChips = 0; - o2::trk::ChipSimResponse* mChipSimResp = nullptr; // simulated response - o2::trk::ChipSimResponse* mChipSimRespVD = nullptr; // simulated response for VD chips - o2::trk::ChipSimResponse* mChipSimRespMLOT = nullptr; // simulated response for ML/OT chips - - // std::string mResponseFile = "$(O2_ROOT)/share/Detectors/ITSMFT/data/AlpideResponseData/AlpideResponseData.root"; - std::string mResponseFile = "$(O2_ROOT)/share/Detectors/Upgrades/ITS3/data/ITS3ChipResponseData/APTSResponseData.root"; /// using temporarly the APTS response + const o2::trk::ChipSimResponse* mChipSimResp = nullptr; // simulated response + const o2::trk::ChipSimResponse* mChipSimRespVD = nullptr; // simulated response for VD chips + const o2::trk::ChipSimResponse* mChipSimRespMLOT = nullptr; // simulated response for ML/OT chips bool mSimRespOrientation{false}; // wether the orientation in the response function is flipped float mSimRespVDShift{0.f}; // adjusting the Y-shift in the APTS response function to match sensor local coord. diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx index df6f46ac0ecb0..ca4685d53de2a 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx @@ -12,9 +12,10 @@ /// \file DigiParams.cxx /// \brief Implementation of the TRK digitization steering params. Based on the ITS2 code. -#include // for LOG -#include "TRKSimulation/DigiParams.h" #include +#include "Framework/Logger.h" +#include "TRKSimulation/DigiParams.h" +#include "TRKSimulation/ChipSimResponse.h" using namespace o2::trk; @@ -70,3 +71,11 @@ void DigiParams::print() const printf("Charge time-response:\n"); mSignalShape.print(); } + +void DigiParams::setAlpSimResponse(const o2::itsmft::AlpideSimResponse* resp) +{ + if (!resp) { + LOGP(fatal, "cannot set response function from null"); + } + mAlpSimResponse = std::make_unique(resp); +} diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx index 20509782f21ee..3ee952801f0c3 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx @@ -48,15 +48,9 @@ void Digitizer::init() mChips[i].setDeadChanMap(mDeadChanMap); } } - // importing the charge collection tables - // (initialized while building O2) - auto file = TFile::Open(mResponseFile.data()); - if (!file) { - LOG(fatal) << "Cannot open response file " << mResponseFile; - } // setting the correct response function (for the moment, for both VD and MLOT the APTS response function is udes) - mChipSimResp = (o2::trk::ChipSimResponse*)file->Get("response1"); + mChipSimResp = mParams.getAlpSimResponse(); mChipSimRespVD = mChipSimResp; /// for the moment considering the same response mChipSimRespMLOT = mChipSimResp; /// for the moment considering the same response @@ -92,7 +86,7 @@ void Digitizer::init() mIRFirstSampledTF = o2::raw::HBFUtils::Instance().getFirstSampledTFIR(); } -o2::trk::ChipSimResponse* Digitizer::getChipResponse(int chipID) +const o2::trk::ChipSimResponse* Digitizer::getChipResponse(int chipID) { if (mGeometry->getSubDetID(chipID) == 0) { /// VD return mChipSimRespVD; diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKSimulationLinkDef.h b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKSimulationLinkDef.h index 9af868a2de44c..fec9cb6631a6f 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKSimulationLinkDef.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKSimulationLinkDef.h @@ -24,6 +24,7 @@ #pragma link C++ class o2::trk::Detector + ; #pragma link C++ class o2::base::DetImpl < o2::trk::Detector> + ; #pragma link C++ class o2::trk::Digitizer + ; +#pragma link C++ class o2::trk::ChipSimResponse + ; #pragma link C++ class o2::trk::DPLDigitizerParam < o2::detectors::DetID::TRK> + ; #pragma link C++ class o2::trk::DPLDigitizerParam < o2::detectors::DetID::FT3> + ; diff --git a/Detectors/Upgrades/ITS3/CMakeLists.txt b/Detectors/Upgrades/ITS3/CMakeLists.txt index 5e40e59ad0068..bdaf1b4bf4292 100644 --- a/Detectors/Upgrades/ITS3/CMakeLists.txt +++ b/Detectors/Upgrades/ITS3/CMakeLists.txt @@ -12,7 +12,6 @@ #add_compile_options(-O0 -g -fPIC -fsanitize=address) #add_link_options(-fsanitize=address) -add_subdirectory(data) add_subdirectory(simulation) add_subdirectory(alignment) add_subdirectory(base) diff --git a/Detectors/Upgrades/ITS3/data/CMakeLists.txt b/Detectors/Upgrades/ITS3/data/CMakeLists.txt deleted file mode 100644 index 7a807fd670370..0000000000000 --- a/Detectors/Upgrades/ITS3/data/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2019-2020 CERN and copyright holders of ALICE O2. -# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -# All rights not expressly granted are reserved. -# -# This software is distributed under the terms of the GNU General Public -# License v3 (GPL Version 3), copied verbatim in the file "COPYING". -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization -# or submit itself to any jurisdiction. - -set(APTS_RESPONSE_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/APTSResponseData.root") - -add_custom_command( - OUTPUT ${APTS_RESPONSE_OUTPUT} - COMMAND ${CMAKE_BINARY_DIR}/stage/bin/o2-alpide-response-generator - -c APTS - -i ${ITSRESPONSE_DIR}/response/ITS3ChipResponseData/AptsResponseData/ - -o ${CMAKE_CURRENT_BINARY_DIR}/ - DEPENDS GenerateAlpideResponse - ${ITSRESPONSE_DIR}/response/ITS3ChipResponseData/AptsResponseData/ - COMMENT "Generating APTSResponseData.root" - VERBATIM -) - -add_custom_target( - GenerateAPTSResponse ALL - DEPENDS ${APTS_RESPONSE_OUTPUT} -) - -install( - FILES ${APTS_RESPONSE_OUTPUT} - DESTINATION "${CMAKE_INSTALL_PREFIX}/share/Detectors/Upgrades/ITS3/data/ITS3ChipResponseData/" -) diff --git a/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/DigiParams.h b/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/DigiParams.h index 5764dfbd7d593..e3a2a5d0d0efb 100644 --- a/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/DigiParams.h +++ b/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/DigiParams.h @@ -48,16 +48,17 @@ class DigiParams final : public o2::itsmft::DigiParams const o2::itsmft::AlpideSimResponse* getOBSimResponse() const { return mOBSimResponse; } void setOBSimResponse(const o2::itsmft::AlpideSimResponse* response) { mOBSimResponse = response; } - o2::its3::ChipSimResponse* getIBSimResponse() const { return mIBSimResponse; } - void setIBSimResponse(o2::its3::ChipSimResponse* response); + o2::its3::ChipSimResponse* getIBSimResponse() const { return mIBSimResponse.get(); } + void setIBSimResponse(const o2::itsmft::AlpideSimResponse* resp); bool hasResponseFunctions() const { return mIBSimResponse != nullptr && mOBSimResponse != nullptr; } void print() const final; private: - const o2::itsmft::AlpideSimResponse* mOBSimResponse = nullptr; //!< pointer to external response - o2::its3::ChipSimResponse* mIBSimResponse = nullptr; //!< pointer to external response + const o2::itsmft::AlpideSimResponse* mOBSimResponse = nullptr; //!< pointer to external response + const o2::itsmft::AlpideSimResponse* mIBSimResponseExt = nullptr; //!< pointer to external response + std::unique_ptr mIBSimResponse = nullptr; //!< pointer to external response ClassDef(DigiParams, 1); }; diff --git a/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/Digitizer.h b/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/Digitizer.h index a2dd1102091da..866973083983b 100644 --- a/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/Digitizer.h +++ b/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/Digitizer.h @@ -42,7 +42,7 @@ class Digitizer : public TObject using ExtraDig = std::vector; ///< container for extra contributions to PreDigits public: - ~Digitizer(); + ~Digitizer() = default; void setDigits(std::vector* dig) { mDigits = dig; } void setMCLabels(o2::dataformats::MCTruthContainer* mclb) { mMCLabels = mclb; } @@ -111,18 +111,18 @@ class Digitizer : public TObject static constexpr std::array mIBSegmentations{0, 1, 2}; - o2::its3::ChipSimResponse* mSimRespIB = nullptr; // simulated response for IB - o2::itsmft::AlpideSimResponse* mSimRespOB = nullptr; // simulated response for OB - bool mSimRespIBOrientation{false}; // wether the orientation in the IB response function is flipped - float mSimRespIBShift{0.f}; // adjusting the Y-shift in the IB response function to match sensor local coord. - float mSimRespIBScaleX{1.f}; // scale x-local coordinate to response function x-coordinate - float mSimRespIBScaleZ{1.f}; // scale z-local coordinate to response function z-coordinate - float mSimRespOBShift{0.f}; // adjusting the Y-shift in the OB response function to match sensor local coord. + const o2::its3::ChipSimResponse* mSimRespIB = nullptr; // simulated response for IB + const o2::itsmft::AlpideSimResponse* mSimRespOB = nullptr; // simulated response for OB + bool mSimRespIBOrientation{false}; // wether the orientation in the IB response function is flipped + float mSimRespIBShift{0.f}; // adjusting the Y-shift in the IB response function to match sensor local coord. + float mSimRespIBScaleX{1.f}; // scale x-local coordinate to response function x-coordinate + float mSimRespIBScaleZ{1.f}; // scale z-local coordinate to response function z-coordinate + float mSimRespOBShift{0.f}; // adjusting the Y-shift in the OB response function to match sensor local coord. const o2::its::GeometryTGeo* mGeometry = nullptr; ///< ITS3 geometry - std::vector mChips; ///< Array of chips digits containers - std::deque> mExtraBuff; ///< burrer (per roFrame) for extra digits + std::vector mChips; ///< Array of chips digits containers + std::deque> mExtraBuff; ///< burrer (per roFrame) for extra digits std::vector* mDigits = nullptr; //! output digits std::vector* mROFRecords = nullptr; //! output ROF records diff --git a/Detectors/Upgrades/ITS3/simulation/src/DigiParams.cxx b/Detectors/Upgrades/ITS3/simulation/src/DigiParams.cxx index afa02ec44741d..e5923d0bb7a1e 100644 --- a/Detectors/Upgrades/ITS3/simulation/src/DigiParams.cxx +++ b/Detectors/Upgrades/ITS3/simulation/src/DigiParams.cxx @@ -69,12 +69,14 @@ void DigiParams::print() const getSignalShape().print(); } -void DigiParams::setIBSimResponse(o2::its3::ChipSimResponse* response) +void DigiParams::setIBSimResponse(const o2::itsmft::AlpideSimResponse* resp) { - mIBSimResponse = response; - if (mIBSimResponse) { - mIBSimResponse->computeCentreFromData(); + if (!resp) { + LOGP(fatal, "cannot set response from nullptr"); } + mIBSimResponseExt = resp; + mIBSimResponse = std::make_unique(mIBSimResponseExt); + mIBSimResponse->computeCentreFromData(); } } // namespace o2::its3 diff --git a/Detectors/Upgrades/ITS3/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ITS3/simulation/src/Digitizer.cxx index 7dd7110801f4a..4560a656c1762 100644 --- a/Detectors/Upgrades/ITS3/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ITS3/simulation/src/Digitizer.cxx @@ -35,11 +35,6 @@ using o2::itsmft::PreDigit; using namespace o2::its3; -Digitizer::~Digitizer() -{ - delete mSimRespIB; -} - void Digitizer::init() { const int numOfChips = mGeometry->getNumberOfChips(); @@ -53,46 +48,22 @@ void Digitizer::init() } if (!mParams.hasResponseFunctions()) { - auto loadSetResponseFunc = [&](const char* fileIB, const char* nameIB, const char* fileOB, const char* nameOB) { - LOGP(info, "Loading response function IB={}:{} ; OB={}:{}", nameIB, fileIB, nameOB, fileOB); - auto fIB = TFile::Open(fileIB, "READ"); - if (!fIB || fIB->IsZombie() || !fIB->IsOpen()) { - LOGP(fatal, "Cannot open file {}", fileIB); - } - auto fOB = TFile::Open(fileOB, "READ"); - if (!fOB || fOB->IsZombie() || !fOB->IsOpen()) { - LOGP(fatal, "Cannot open file {}", fileOB); - } - if ((mSimRespIB = new o2::its3::ChipSimResponse(fIB->Get(nameIB))) == nullptr) { - LOGP(fatal, "Cannot create response function for IB"); - } - if ((mSimRespOB = fOB->Get(nameOB)) == nullptr) { - LOGP(fatal, "Cannot create response function for OB"); - } - mParams.setIBSimResponse(mSimRespIB); - mParams.setOBSimResponse(mSimRespOB); - fIB->Close(); - fOB->Close(); - }; - - if (const auto& func = ITS3Params::Instance().chipResponseFunction; func == "Alpide") { - constexpr const char* responseFile = "$(O2_ROOT)/share/Detectors/ITSMFT/data/AlpideResponseData/AlpideResponseData.root"; - loadSetResponseFunc(responseFile, "response0", responseFile, "response0"); - mSimRespIBScaleX = o2::itsmft::SegmentationAlpide::PitchRow / SegmentationIB::PitchRow; - mSimRespIBScaleZ = o2::itsmft::SegmentationAlpide::PitchCol / SegmentationIB::PitchCol; - } else if (func == "APTS") { - constexpr const char* responseFileIB = "$(O2_ROOT)/share/Detectors/Upgrades/ITS3/data/ITS3ChipResponseData/APTSResponseData.root"; - constexpr const char* responseFileOB = "$(O2_ROOT)/share/Detectors/ITSMFT/data/AlpideResponseData/AlpideResponseData.root"; - loadSetResponseFunc(responseFileIB, "response1", responseFileOB, "response0"); - mSimRespIBScaleX = constants::pixelarray::pixels::apts::pitchX / SegmentationIB::PitchRow; - mSimRespIBScaleZ = constants::pixelarray::pixels::apts::pitchZ / SegmentationIB::PitchCol; - mSimRespIBOrientation = true; - } else { - LOGP(fatal, "ResponseFunction '{}' not implemented!", func); - } - mSimRespIBShift = mSimRespIB->getDepthMax() - constants::silicon::thickness / 2.f; - mSimRespOBShift = mSimRespOB->getDepthMax() - SegmentationOB::SensorLayerThickness / 2.f; + LOGP(fatal, "No response functions set!"); + } + if (const auto& func = ITS3Params::Instance().chipResponseFunction; func == "Alpide") { + mSimRespIBScaleX = o2::itsmft::SegmentationAlpide::PitchRow / SegmentationIB::PitchRow; + mSimRespIBScaleZ = o2::itsmft::SegmentationAlpide::PitchCol / SegmentationIB::PitchCol; + } else if (func == "APTS") { + mSimRespIBScaleX = constants::pixelarray::pixels::apts::pitchX / SegmentationIB::PitchRow; + mSimRespIBScaleZ = constants::pixelarray::pixels::apts::pitchZ / SegmentationIB::PitchCol; + mSimRespIBOrientation = true; + } else { + LOGP(fatal, "ResponseFunction '{}' not implemented!", func); } + mSimRespIB = mParams.getIBSimResponse(); + mSimRespOB = mParams.getOBSimResponse(); + mSimRespIBShift = mSimRespIB->getDepthMax() - constants::silicon::thickness / 2.f; + mSimRespOBShift = mSimRespOB->getDepthMax() - SegmentationOB::SensorLayerThickness / 2.f; mParams.print(); LOGP(info, "IB shift = {} ; OB shift = {}", mSimRespIBShift, mSimRespOBShift); diff --git a/Steer/DigitizerWorkflow/src/ITS3DigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/ITS3DigitizerSpec.cxx index af0af091d40e8..639203bdd6d38 100644 --- a/Steer/DigitizerWorkflow/src/ITS3DigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/ITS3DigitizerSpec.cxx @@ -254,6 +254,11 @@ class ITS3DPLDigitizerTask : BaseDPLDigitizer pc.inputs().get("IT3_dead"); // trigger final ccdb update } + pc.inputs().get("IT3_alpiderespvbb0"); + if (o2::its3::ITS3Params::Instance().chipResponseFunction != "Alpide") { + pc.inputs().get("IT3_aptsresp"); + } + // init digitizer mDigitizer.init(); } @@ -273,6 +278,14 @@ class ITS3DPLDigitizerTask : BaseDPLDigitizer mDigitizer.setDeadChannelsMap((o2::itsmft::NoiseMap*)obj); return; } + if (matcher == ConcreteDataMatcher(mOrigin, "ALPIDERESPVbb0", 0)) { + LOG(info) << mID.getName() << " loaded AlpideResponseData for Vbb=0V"; + mDigitizer.getParams().setOBSimResponse((o2::itsmft::AlpideSimResponse*)obj); + } + if (matcher == ConcreteDataMatcher(mOrigin, "APTSRESP", 0)) { + LOG(info) << mID.getName() << " loaded APTSResponseData"; + mDigitizer.getParams().setIBSimResponse((o2::itsmft::AlpideSimResponse*)obj); + } } private: @@ -306,6 +319,8 @@ DataProcessorSpec getITS3DigitizerSpec(int channel, bool mctruth) if (o2::its3::ITS3Params::Instance().useDeadChannelMap) { inputs.emplace_back("IT3_dead", "IT3", "DEADMAP", 0, Lifetime::Condition, ccdbParamSpec("IT3/Calib/DeadMap")); } + inputs.emplace_back("IT3_alpiderespvbb0", "IT3", "ALPIDERESPVbb0", 0, Lifetime::Condition, ccdbParamSpec("ITSMFT/Calib/ALPIDEResponseVbb0")); + inputs.emplace_back("IT3_aptsresp", "IT3", "APTSRESP", 0, Lifetime::Condition, ccdbParamSpec("IT3/Calib/APTSResponse")); return DataProcessorSpec{detStr + "Digitizer", inputs, makeOutChannels(detOrig, mctruth), diff --git a/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx index 72ec65b2e522b..b40e377d58ca2 100644 --- a/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx @@ -222,6 +222,14 @@ class ITSMFTDPLDigitizerTask : BaseDPLDigitizer } return; } + if (matcher == ConcreteDataMatcher(mOrigin, "ALPIDERESPVbb0", 0)) { + LOG(info) << mID.getName() << " loaded AlpideResponseData for Vbb=0V"; + mDigitizer.setAlpideResponse((o2::itsmft::AlpideSimResponse*)obj, 0); + } + if (matcher == ConcreteDataMatcher(mOrigin, "ALPIDERESPVbbM3", 0)) { + LOG(info) << mID.getName() << " loaded AlpideResponseData for Vbb=-3V"; + mDigitizer.setAlpideResponse((o2::itsmft::AlpideSimResponse*)obj, 1); + } } protected: @@ -236,6 +244,8 @@ class ITSMFTDPLDigitizerTask : BaseDPLDigitizer // TODO: the code should run even if this object does not exist. Or: create default object pc.inputs().get(detstr + "_time_dead"); pc.inputs().get*>(detstr + "_alppar"); + pc.inputs().get(detstr + "_alpiderespvbb0"); + pc.inputs().get(detstr + "_alpiderespvbbm3"); auto& dopt = o2::itsmft::DPLDigitizerParam::Instance(); auto& aopt = o2::itsmft::DPLAlpideParam::Instance(); @@ -365,6 +375,8 @@ DataProcessorSpec getITSDigitizerSpec(int channel, bool mctruth) inputs.emplace_back("ITS_dead", "ITS", "DEADMAP", 0, Lifetime::Condition, ccdbParamSpec("ITS/Calib/DeadMap")); inputs.emplace_back("ITS_time_dead", "ITS", "TimeDeadMap", 0, Lifetime::Condition, ccdbParamSpec("ITS/Calib/TimeDeadMap")); inputs.emplace_back("ITS_alppar", "ITS", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/AlpideParam")); + inputs.emplace_back("ITS_alpiderespvbb0", "ITS", "ALPIDERESPVbb0", 0, Lifetime::Condition, ccdbParamSpec("ITSMFT/Calib/ALPIDEResponseVbb0")); + inputs.emplace_back("ITS_alpiderespvbbm3", "ITS", "ALPIDERESPVbbM3", 0, Lifetime::Condition, ccdbParamSpec("ITSMFT/Calib/ALPIDEResponseVbbM3")); return DataProcessorSpec{(detStr + "Digitizer").c_str(), inputs, makeOutChannels(detOrig, mctruth), @@ -384,6 +396,8 @@ DataProcessorSpec getMFTDigitizerSpec(int channel, bool mctruth) inputs.emplace_back("MFT_dead", "MFT", "DEADMAP", 0, Lifetime::Condition, ccdbParamSpec("MFT/Calib/DeadMap")); inputs.emplace_back("MFT_time_dead", "MFT", "TimeDeadMap", 0, Lifetime::Condition, ccdbParamSpec("MFT/Calib/TimeDeadMap")); inputs.emplace_back("MFT_alppar", "MFT", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("MFT/Config/AlpideParam")); + inputs.emplace_back("MFT_alpiderespvbb0", "MFT", "ALPIDERESPVbb0", 0, Lifetime::Condition, ccdbParamSpec("ITSMFT/Calib/ALPIDEResponseVbb0")); + inputs.emplace_back("MFT_alpiderespvbbm3", "MFT", "ALPIDERESPVbbM3", 0, Lifetime::Condition, ccdbParamSpec("ITSMFT/Calib/ALPIDEResponseVbbM3")); parHelper << "Params as " << o2::itsmft::DPLDigitizerParam::getParamName().data() << ".=value;... with" << o2::itsmft::DPLDigitizerParam::Instance() << " or " << o2::itsmft::DPLAlpideParam::getParamName().data() << ".=value;... with" diff --git a/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx index 37355cb5752c4..a3d4d1f245fc5 100644 --- a/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx @@ -244,6 +244,7 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer // if (oTRKParams::Instance().useDeadChannelMap) { // pc.inputs().get("TRK_dead"); // trigger final ccdb update // } + pc.inputs().get("TRK_aptsresp"); // init digitizer mDigitizer.init(); @@ -264,6 +265,10 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer // mDigitizer.setDeadChannelsMap((o2::itsmft::NoiseMap*)obj); // return; // } + if (matcher == ConcreteDataMatcher(mOrigin, "APTSRESP", 0)) { + LOG(info) << mID.getName() << " loaded APTSResponseData"; + mDigitizer.getParams().setAlpSimResponse((const o2::itsmft::AlpideSimResponse*)obj); + } } private: @@ -297,6 +302,7 @@ DataProcessorSpec getTRKDigitizerSpec(int channel, bool mctruth) // if (oTRKParams::Instance().useDeadChannelMap) { // inputs.emplace_back("TRK_dead", "TRK", "DEADMAP", 0, Lifetime::Condition, ccdbParamSpec("TRK/Calib/DeadMap")); // } + inputs.emplace_back("TRK_aptsresp", "TRK", "APTSRESP", 0, Lifetime::Condition, ccdbParamSpec("IT3/Calib/APTSResponse")); return DataProcessorSpec{detStr + "Digitizer", inputs, makeOutChannels(detOrig, mctruth), From 1bcfeed348dd3bbc16345b622f2d03bc1626f0c0 Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Tue, 16 Dec 2025 12:40:18 +0100 Subject: [PATCH 022/234] Update CODEOWNERS --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 117ff0d92b272..26021d458ad76 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -34,7 +34,7 @@ /DataFormats/Detectors/GlobalTracking @shahor02 /DataFormats/Detectors/GlobalTrackingWorkflow @shahor02 /DataFormats/Detectors/HMPID @gvolpe79 -/DataFormats/Detectors/ITSMFT @fprino @mcoquet642 @mconcas @shahor02 +/DataFormats/Detectors/ITSMFT @fprino @mcoquet642 @shahor02 /DataFormats/Detectors/MUON @AliceO2Group/muon-experts @shahor02 /DataFormats/Detectors/PHOS @peressounko @kharlov /DataFormats/Detectors/Passive @sawenzel From 528a5a59130c425ad933531cc65a54dc371e28ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Jacazio?= Date: Tue, 16 Dec 2025 16:50:47 +0100 Subject: [PATCH 023/234] Refine parameter getter methods with error handling (#14794) Updated getter functions to specify return types and added error logging for missing parameters. --- .../TOF/include/DataFormatsTOF/ParameterContainers.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/DataFormats/Detectors/TOF/include/DataFormatsTOF/ParameterContainers.h b/DataFormats/Detectors/TOF/include/DataFormatsTOF/ParameterContainers.h index e64bf8aa3e276..224906e43b8c6 100644 --- a/DataFormats/Detectors/TOF/include/DataFormatsTOF/ParameterContainers.h +++ b/DataFormats/Detectors/TOF/include/DataFormatsTOF/ParameterContainers.h @@ -210,7 +210,13 @@ class ParameterCollection : public TNamed } /// @brief getter for the parameters stored in the container matching to a pass - const auto& getPars(const std::string& pass) const { return mParameters.at(pass); } + const std::unordered_map& getPars(const std::string& pass) const + { + if (!hasKey(pass)) { + LOG(fatal) << "Parameters for pass " << pass << " not found!"; + } + return mParameters.at(pass); + } /// @brief printing function for the content of the pass /// @param pass pass to print @@ -221,7 +227,7 @@ class ParameterCollection : public TNamed /// @brief Getter of the full map of parameters stored in the container /// @return returns the full map of parameters - const auto& getFullMap() { return mParameters; } + const std::unordered_map>& getFullMap() const { return mParameters; } /// Loader from file /// \param FileName name of the input file From 70b10405ca2ffe3103bc01b26fde13b1a13ea6c9 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Tue, 16 Dec 2025 22:02:47 +0100 Subject: [PATCH 024/234] DPL: modernize workflow construction code using ranges (#14907) --- .../Framework/AnalysisSupportHelpers.h | 5 - .../Core/include/Framework/DataSpecViews.h | 43 +++++- Framework/Core/src/AnalysisSupportHelpers.cxx | 127 +++++------------- Framework/Core/src/ArrowSupport.cxx | 60 +++------ Framework/Core/src/WorkflowHelpers.cxx | 64 +++------ 5 files changed, 114 insertions(+), 185 deletions(-) diff --git a/Framework/Core/include/Framework/AnalysisSupportHelpers.h b/Framework/Core/include/Framework/AnalysisSupportHelpers.h index cc4d45a46c8bc..c0eeb3bd9697d 100644 --- a/Framework/Core/include/Framework/AnalysisSupportHelpers.h +++ b/Framework/Core/include/Framework/AnalysisSupportHelpers.h @@ -39,11 +39,6 @@ struct AnalysisSupportHelpers { std::vector const& requestedSpecials, std::vector& requestedAODs, DataProcessorSpec& publisher); - static void addMissingOutputsToAnalysisCCDBFetcher(std::vector const& providedSpecials, - std::vector const& requestedSpecials, - std::vector& requestedAODs, - std::vector& requestedDYNs, - DataProcessorSpec& publisher); static void addMissingOutputsToBuilder(std::vector const& requestedSpecials, std::vector& requestedAODs, std::vector& requestedDYNs, diff --git a/Framework/Core/include/Framework/DataSpecViews.h b/Framework/Core/include/Framework/DataSpecViews.h index 0782cefd0f632..162a12419594e 100644 --- a/Framework/Core/include/Framework/DataSpecViews.h +++ b/Framework/Core/include/Framework/DataSpecViews.h @@ -31,6 +31,32 @@ static auto filter_not_matching(auto const& provided) return std::views::filter([&provided](auto const& input) { return std::none_of(provided.begin(), provided.end(), [&input](auto const& output) { return DataSpecUtils::match(input, output); }); }); } +static auto filter_matching(auto const& provided) +{ + return std::views::filter([&provided](auto const& input) { return std::any_of(provided.begin(), provided.end(), [&input](auto const& output) { return DataSpecUtils::match(input, output); }); }); +} + +static auto filter_string_params_with(std::string match) +{ + return std::views::filter([match](auto const& param) { + return (param.type == VariantType::String) && (param.name.find(match) != std::string::npos); + }); +} + +static auto input_to_output_specs() +{ + return std::views::transform([](auto const& input) { + auto concrete = DataSpecUtils::asConcreteDataMatcher(input); + return OutputSpec{concrete.origin, concrete.description, concrete.subSpec, input.lifetime, input.metadata}; + }); +} + +static auto params_to_input_specs() +{ + return std::views::transform([](auto const& param) { + return DataSpecUtils::fromMetadataString(param.defaultValue.template get()); + }); +} } // namespace o2::framework::views // namespace o2::framework::sinks @@ -54,7 +80,7 @@ struct update_input_list { template friend Container& operator|(R&& r, update_input_list self) { - for (auto& item : r) { + for (auto const& item : r) { auto copy = item; DataSpecUtils::updateInputList(self.c, std::move(copy)); } @@ -62,6 +88,21 @@ struct update_input_list { } }; +template +struct update_output_list { + Container& c; + // ends the pipeline, returns the container + template + friend Container& operator|(R&& r, update_output_list self) + { + for (auto const& item : r) { + auto copy = item; + DataSpecUtils::updateOutputList(self.c, std::move(copy)); + } + return self.c; + } +}; + } // namespace o2::framework::sinks #endif // O2_FRAMEWORK_DATASPECVIEWS_H_ diff --git a/Framework/Core/src/AnalysisSupportHelpers.cxx b/Framework/Core/src/AnalysisSupportHelpers.cxx index b5c898faa515a..e59f36c72bdab 100644 --- a/Framework/Core/src/AnalysisSupportHelpers.cxx +++ b/Framework/Core/src/AnalysisSupportHelpers.cxx @@ -11,10 +11,7 @@ #include "Framework/AnalysisSupportHelpers.h" #include "Framework/DataOutputDirector.h" -#include "Framework/OutputObjHeader.h" -#include "Framework/ControlService.h" -#include "Framework/EndOfStreamContext.h" -#include "Framework/DeviceSpec.h" +#include "Framework/DataSpecViews.h" #include "Framework/PluginManager.h" #include "Framework/ConfigContext.h" #include "WorkflowHelpers.h" @@ -129,30 +126,11 @@ void AnalysisSupportHelpers::addMissingOutputsToReader(std::vector c std::vector const& requestedInputs, DataProcessorSpec& publisher) { - auto matchingOutputFor = [](InputSpec const& requested) { - return [&requested](OutputSpec const& provided) { - return DataSpecUtils::match(requested, provided); - }; - }; - for (InputSpec const& requested : requestedInputs) { - auto provided = std::find_if(providedOutputs.begin(), - providedOutputs.end(), - matchingOutputFor(requested)); - - if (provided != providedOutputs.end()) { - continue; - } - - auto inList = std::find_if(publisher.outputs.begin(), - publisher.outputs.end(), - matchingOutputFor(requested)); - if (inList != publisher.outputs.end()) { - continue; - } - - auto concrete = DataSpecUtils::asConcreteDataMatcher(requested); - publisher.outputs.emplace_back(concrete.origin, concrete.description, concrete.subSpec, requested.lifetime, requested.metadata); - } + requestedInputs | + views::filter_not_matching(providedOutputs) | // filter the inputs that are already provided + views::filter_not_matching(publisher.outputs) | // filter the inputs that are already covered + views::input_to_output_specs() | + sinks::append_to{publisher.outputs}; // append them to the publisher outputs } void AnalysisSupportHelpers::addMissingOutputsToSpawner(std::vector const& providedSpecials, @@ -160,25 +138,20 @@ void AnalysisSupportHelpers::addMissingOutputsToSpawner(std::vector std::vector& requestedAODs, DataProcessorSpec& publisher) { - for (auto& input : requestedSpecials) { - if (std::any_of(providedSpecials.begin(), providedSpecials.end(), [&input](auto const& x) { - return DataSpecUtils::match(input, x); - })) { - continue; - } - auto concrete = DataSpecUtils::asConcreteDataMatcher(input); - publisher.outputs.emplace_back(concrete.origin, concrete.description, concrete.subSpec); - for (auto& i : input.metadata) { - if ((i.type == VariantType::String) && (i.name.find("input:") != std::string::npos)) { - auto spec = DataSpecUtils::fromMetadataString(i.defaultValue.get()); - auto j = std::find(publisher.inputs.begin(), publisher.inputs.end(), spec); - if (j == publisher.inputs.end()) { - publisher.inputs.push_back(spec); - } - DataSpecUtils::updateInputList(requestedAODs, std::move(spec)); - } - } + requestedSpecials | + views::filter_not_matching(providedSpecials) | // filter the inputs that are already provided + views::input_to_output_specs() | + sinks::append_to{publisher.outputs}; // append them to the publisher outputs + + std::vector additionalInputs; + for (auto& input : requestedSpecials | views::filter_not_matching(providedSpecials)) { + input.metadata | + views::filter_string_params_with("input:") | + views::params_to_input_specs() | + sinks::update_input_list{additionalInputs}; // store into a temporary } + additionalInputs | sinks::update_input_list{requestedAODs}; // update requestedAODs + additionalInputs | sinks::update_input_list{publisher.inputs}; // update publisher inputs } void AnalysisSupportHelpers::addMissingOutputsToBuilder(std::vector const& requestedSpecials, @@ -186,52 +159,26 @@ void AnalysisSupportHelpers::addMissingOutputsToBuilder(std::vector c std::vector& requestedDYNs, DataProcessorSpec& publisher) { - for (auto& input : requestedSpecials) { - auto concrete = DataSpecUtils::asConcreteDataMatcher(input); - publisher.outputs.emplace_back(concrete.origin, concrete.description, concrete.subSpec); - for (auto& i : input.metadata) { - if ((i.type == VariantType::String) && (i.name.find("input:") != std::string::npos)) { - auto spec = DataSpecUtils::fromMetadataString(i.defaultValue.get()); - auto j = std::find_if(publisher.inputs.begin(), publisher.inputs.end(), [&](auto x) { return x.binding == spec.binding; }); - if (j == publisher.inputs.end()) { - publisher.inputs.push_back(spec); - } - if (DataSpecUtils::partialMatch(spec, AODOrigins)) { - DataSpecUtils::updateInputList(requestedAODs, std::move(spec)); - } else if (DataSpecUtils::partialMatch(spec, header::DataOrigin{"DYN"})) { - DataSpecUtils::updateInputList(requestedDYNs, std::move(spec)); - } - } - } + requestedSpecials | + views::input_to_output_specs() | + sinks::append_to{publisher.outputs}; // append them to the publisher outputs + + std::vector additionalInputs; + for (auto const& input : requestedSpecials) { + input.metadata | + views::filter_string_params_with("input:") | + views::params_to_input_specs() | + sinks::update_input_list{additionalInputs}; // store into a temporary } -} -void AnalysisSupportHelpers::addMissingOutputsToAnalysisCCDBFetcher( - std::vector const& providedSpecials, - std::vector const& requestedSpecials, - std::vector& requestedAODs, - std::vector& requestedDYNs, - DataProcessorSpec& publisher) -{ - for (auto& input : requestedSpecials) { - auto concrete = DataSpecUtils::asConcreteDataMatcher(input); - publisher.outputs.emplace_back(concrete.origin, concrete.description, concrete.subSpec); - // FIXME: good enough for now... - for (auto& i : input.metadata) { - if ((i.type == VariantType::String) && (i.name.find("input:") != std::string::npos)) { - auto spec = DataSpecUtils::fromMetadataString(i.defaultValue.get()); - auto j = std::find_if(publisher.inputs.begin(), publisher.inputs.end(), [&](auto x) { return x.binding == spec.binding; }); - if (j == publisher.inputs.end()) { - publisher.inputs.push_back(spec); - } - if (DataSpecUtils::partialMatch(spec, AODOrigins)) { - DataSpecUtils::updateInputList(requestedAODs, std::move(spec)); - } else if (DataSpecUtils::partialMatch(spec, header::DataOrigin{"DYN"})) { - DataSpecUtils::updateInputList(requestedDYNs, std::move(spec)); - } - } - } - } + additionalInputs | sinks::update_input_list{publisher.inputs}; // update publisher inputs + // FIXME: until we have a single list of pairs + additionalInputs | + views::partial_match_filter(AODOrigins) | + sinks::update_input_list{requestedAODs}; // update requestedAODs + additionalInputs | + views::partial_match_filter(header::DataOrigin{"DYN"}) | + sinks::update_input_list{requestedDYNs}; // update requestedDYNs } // ============================================================================= diff --git a/Framework/Core/src/ArrowSupport.cxx b/Framework/Core/src/ArrowSupport.cxx index cf2d364027932..26594252e888b 100644 --- a/Framework/Core/src/ArrowSupport.cxx +++ b/Framework/Core/src/ArrowSupport.cxx @@ -595,23 +595,16 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() ac.providedTIMs.clear(); ac.requestedTIMs.clear(); - auto inputSpecLessThan = [](InputSpec const& lhs, InputSpec const& rhs) { return DataSpecUtils::describe(lhs) < DataSpecUtils::describe(rhs); }; auto outputSpecLessThan = [](OutputSpec const& lhs, OutputSpec const& rhs) { return DataSpecUtils::describe(lhs) < DataSpecUtils::describe(rhs); }; if (builder != workflow.end()) { // collect currently requested IDXs ac.requestedIDXs.clear(); - for (auto& d : workflow) { - if (d.name == builder->name) { - continue; - } - for (auto& i : d.inputs) { - if (DataSpecUtils::partialMatch(i, header::DataOrigin{"IDX"})) { - auto copy = i; - DataSpecUtils::updateInputList(ac.requestedIDXs, std::move(copy)); - } - } + for (auto& d : workflow | views::exclude_by_name(builder->name)) { + d.inputs | + views::partial_match_filter(header::DataOrigin{"IDX"}) | + sinks::update_input_list{ac.requestedIDXs}; } // recreate inputs and outputs builder->inputs.clear(); @@ -624,37 +617,27 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() if (spawner != workflow.end()) { // collect currently requested DYNs - for (auto& d : workflow) { - if (d.name == spawner->name) { - continue; - } - for (auto const& i : d.inputs) { - if (DataSpecUtils::partialMatch(i, header::DataOrigin{"DYN"})) { - auto copy = i; - DataSpecUtils::updateInputList(ac.requestedDYNs, std::move(copy)); - } - } - for (auto const& o : d.outputs) { - if (DataSpecUtils::partialMatch(o, header::DataOrigin{"DYN"})) { - ac.providedDYNs.emplace_back(o); - } - } + for (auto& d : workflow | views::exclude_by_name(spawner->name)) { + d.inputs | + views::partial_match_filter(header::DataOrigin{"DYN"}) | + sinks::update_input_list{ac.requestedDYNs}; + d.outputs | + views::partial_match_filter(header::DataOrigin{"DYN"}) | + sinks::append_to{ac.providedDYNs}; } std::sort(ac.requestedDYNs.begin(), ac.requestedDYNs.end(), inputSpecLessThan); std::sort(ac.providedDYNs.begin(), ac.providedDYNs.end(), outputSpecLessThan); ac.spawnerInputs.clear(); - for (auto& input : ac.requestedDYNs) { - if (std::none_of(ac.providedDYNs.begin(), ac.providedDYNs.end(), [&input](auto const& x) { return DataSpecUtils::match(input, x); })) { - ac.spawnerInputs.emplace_back(input); - } - } + ac.requestedDYNs | + views::filter_not_matching(ac.providedDYNs) | + sinks::append_to{ac.spawnerInputs}; // recreate inputs and outputs spawner->outputs.clear(); spawner->inputs.clear(); + AnalysisSupportHelpers::addMissingOutputsToSpawner({}, ac.spawnerInputs, ac.requestedAODs, *spawner); // replace AlgorithmSpec // FIXME: it should be made more generic, so it does not need replacement... spawner->algorithm = PluginManager::loadAlgorithmFromPlugin("O2FrameworkOnDemandTablesSupport", "ExtendedTableSpawner", ctx); - AnalysisSupportHelpers::addMissingOutputsToSpawner({}, ac.spawnerInputs, ac.requestedAODs, *spawner); } if (analysisCCDB != workflow.end()) { @@ -675,7 +658,7 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() // FIXME: it should be made more generic, so it does not need replacement... // FIXME how can I make the lookup depend on DYN tables as well?? analysisCCDB->algorithm = PluginManager::loadAlgorithmFromPlugin("O2FrameworkCCDBSupport", "AnalysisCCDBFetcherPlugin", ctx); - AnalysisSupportHelpers::addMissingOutputsToAnalysisCCDBFetcher({}, ac.analysisCCDBInputs, ac.requestedAODs, ac.requestedDYNs, *analysisCCDB); + AnalysisSupportHelpers::addMissingOutputsToBuilder(ac.analysisCCDBInputs, ac.requestedAODs, ac.requestedDYNs, *analysisCCDB); } if (writer != workflow.end()) { @@ -686,12 +669,9 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() // If reader and/or builder were adjusted, remove unneeded outputs // update currently requested AODs for (auto& d : workflow) { - for (auto const& i : d.inputs) { - if (DataSpecUtils::partialMatch(i, AODOrigins)) { - auto copy = i; - DataSpecUtils::updateInputList(ac.requestedAODs, std::move(copy)); - } - } + d.inputs | + views::partial_match_filter(AODOrigins) | + sinks::update_input_list{ac.requestedAODs}; } // remove unmatched outputs @@ -705,8 +685,6 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() } } - - // replace writer as some outputs may have become dangling and some are now consumed auto [outputsInputs, isDangling] = WorkflowHelpers::analyzeOutputs(workflow); diff --git a/Framework/Core/src/WorkflowHelpers.cxx b/Framework/Core/src/WorkflowHelpers.cxx index 17f6c9eb7ddb6..02141678fec7c 100644 --- a/Framework/Core/src/WorkflowHelpers.cxx +++ b/Framework/Core/src/WorkflowHelpers.cxx @@ -19,7 +19,6 @@ #include "Framework/DataSpecUtils.h" #include "Framework/DataSpecViews.h" #include "Framework/DataAllocator.h" -#include "Framework/ControlService.h" #include "Framework/RawDeviceService.h" #include "Framework/StringHelpers.h" #include "Framework/ChannelSpecHelpers.h" @@ -157,18 +156,6 @@ int defaultConditionQueryRateMultiplier() void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext& ctx) { - auto fakeCallback = AlgorithmSpec{[](InitContext& ic) { - LOG(info) << "This is not a real device, merely a placeholder for external inputs"; - LOG(info) << "To be hidden / removed at some point."; - // mark this dummy process as ready-to-quit - ic.services().get().readyToQuit(QuitRequest::Me); - - return [](ProcessingContext& pc) { - // this callback is never called since there is no expiring input - pc.services().get().waitFor(2000); - }; - }}; - DataProcessorSpec ccdbBackend{ .name = "internal-dpl-ccdb-backend", .outputs = {}, @@ -281,20 +268,9 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext processor.options.push_back(ConfigParamSpec{"end-value-enumeration", VariantType::Int64, -1ll, {"final value for the enumeration"}}); processor.options.push_back(ConfigParamSpec{"step-value-enumeration", VariantType::Int64, 1ll, {"step between one value and the other"}}); } - bool hasTimeframeInputs = false; - for (auto& input : processor.inputs) { - if (input.lifetime == Lifetime::Timeframe) { - hasTimeframeInputs = true; - break; - } - } - bool hasTimeframeOutputs = false; - for (auto& output : processor.outputs) { - if (output.lifetime == Lifetime::Timeframe) { - hasTimeframeOutputs = true; - break; - } - } + bool hasTimeframeInputs = std::any_of(processor.inputs.begin(), processor.inputs.end(), [](auto const& input) { return input.lifetime == Lifetime::Timeframe; }); + bool hasTimeframeOutputs = std::any_of(processor.outputs.begin(), processor.outputs.end(), [](auto const& output) { return output.lifetime == Lifetime::Timeframe; }); + // A timeframeSink consumes timeframes without creating new // timeframe data. bool timeframeSink = hasTimeframeInputs && !hasTimeframeOutputs; @@ -304,14 +280,13 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext uint32_t hash = runtime_hash(processor.name.c_str()); bool hasMatch = false; ConcreteDataMatcher summaryMatcher = ConcreteDataMatcher{"DPL", "SUMMARY", static_cast(hash)}; - for (auto& output : processor.outputs) { - if (DataSpecUtils::match(output, summaryMatcher)) { - O2_SIGNPOST_EVENT_EMIT(workflow_helpers, sid, "output enumeration", "%{public}s already there in %{public}s", - DataSpecUtils::describe(output).c_str(), processor.name.c_str()); - hasMatch = true; - break; - } + auto summaryOutput = std::find_if(processor.outputs.begin(), processor.outputs.end(), [&summaryMatcher](auto const& output) { return DataSpecUtils::match(output, summaryMatcher); }); + if (summaryOutput != processor.outputs.end()) { + O2_SIGNPOST_EVENT_EMIT(workflow_helpers, sid, "output enumeration", "%{public}s already there in %{public}s", + DataSpecUtils::describe(*summaryOutput).c_str(), processor.name.c_str()); + hasMatch = true; } + if (!hasMatch) { O2_SIGNPOST_EVENT_EMIT(workflow_helpers, sid, "output enumeration", "Adding DPL/SUMMARY/%d to %{public}s", hash, processor.name.c_str()); processor.outputs.push_back(OutputSpec{{"dpl-summary"}, ConcreteDataMatcher{"DPL", "SUMMARY", static_cast(hash)}}); @@ -339,18 +314,12 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext timer.outputs.emplace_back(OutputSpec{concrete.origin, concrete.description, concrete.subSpec, Lifetime::Enumeration}); } break; case Lifetime::Condition: { - for (auto& option : processor.options) { - if (option.name == "condition-backend") { - hasConditionOption = true; - break; - } - } - if (hasConditionOption == false) { + requestedCCDBs.emplace_back(input); + if ((hasConditionOption == false) && std::none_of(processor.options.begin(), processor.options.end(), [](auto const& option) { return (option.name.compare("condition-backend") == 0); })) { processor.options.emplace_back(ConfigParamSpec{"condition-backend", VariantType::String, defaultConditionBackend(), {"URL for CCDB"}}); processor.options.emplace_back(ConfigParamSpec{"condition-timestamp", VariantType::Int64, 0ll, {"Force timestamp for CCDB lookup"}}); hasConditionOption = true; } - requestedCCDBs.emplace_back(input); } break; case Lifetime::OutOfBand: { auto concrete = DataSpecUtils::asConcreteDataMatcher(input); @@ -422,14 +391,10 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext ac.requestedTIMs | views::filter_not_matching(ac.providedTIMs) | sinks::append_to{ac.analysisCCDBInputs}; DeploymentMode deploymentMode = DefaultsHelpers::deploymentMode(); if (deploymentMode != DeploymentMode::OnlineDDS && deploymentMode != DeploymentMode::OnlineECS) { - AnalysisSupportHelpers::addMissingOutputsToAnalysisCCDBFetcher({}, ac.analysisCCDBInputs, ac.requestedAODs, ac.requestedTIMs, analysisCCDBBackend); + AnalysisSupportHelpers::addMissingOutputsToBuilder(ac.analysisCCDBInputs, ac.requestedAODs, ac.requestedTIMs, analysisCCDBBackend); } - for (auto& input : ac.requestedDYNs) { - if (std::none_of(ac.providedDYNs.begin(), ac.providedDYNs.end(), [&input](auto const& x) { return DataSpecUtils::match(input, x); })) { - ac.spawnerInputs.emplace_back(input); - } - } + ac.requestedDYNs | views::filter_not_matching(ac.providedDYNs) | sinks::append_to{ac.spawnerInputs}; DataProcessorSpec aodSpawner{ "internal-dpl-aod-spawner", @@ -440,6 +405,9 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext AnalysisSupportHelpers::addMissingOutputsToSpawner({}, ac.spawnerInputs, ac.requestedAODs, aodSpawner); AnalysisSupportHelpers::addMissingOutputsToReader(ac.providedAODs, ac.requestedAODs, aodReader); + + std::sort(requestedCCDBs.begin(), requestedCCDBs.end(), inputSpecLessThan); + std::sort(providedCCDBs.begin(), providedCCDBs.end(), outputSpecLessThan); AnalysisSupportHelpers::addMissingOutputsToReader(providedCCDBs, requestedCCDBs, ccdbBackend); std::vector extraSpecs; From a8feeedb8e05bc06b6fd4186199a2cfc7fe89204 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 17 Dec 2025 09:13:23 +0100 Subject: [PATCH 025/234] Avoid early initialization of Cling Requires v6-36-04-alice7 in order to compile / work. --- .../TPC/base/src/TPCFlagsMemberCustomStreamer.cxx | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Detectors/TPC/base/src/TPCFlagsMemberCustomStreamer.cxx b/Detectors/TPC/base/src/TPCFlagsMemberCustomStreamer.cxx index dca7ba35004c9..27ebfeb3c64bb 100644 --- a/Detectors/TPC/base/src/TPCFlagsMemberCustomStreamer.cxx +++ b/Detectors/TPC/base/src/TPCFlagsMemberCustomStreamer.cxx @@ -71,16 +71,10 @@ namespace ROOT { static __attribute__((used)) int _R__dummyStreamer_3 = ([]() { - auto cl = TClass::GetClass>(); - if (cl) { - if (!getenv("TPC_PADFLAGS_STREAMER_OFF")) { - cl->AdoptMemberStreamer("mData", new TMemberStreamer(MemberVectorPadFlagsStreamer)); - } - } else { - // we should never come here ... and if we do we should assert/fail - assert(false); + if (!getenv("TPC_PADFLAGS_STREAMER_OFF")) { + ROOT::GenerateInitInstance((o2::tpc::CalArray *)nullptr)->AdoptMemberStreamer("mData", new TMemberStreamer(MemberVectorPadFlagsStreamer)); } return 0; })(); } // namespace ROOT -#endif \ No newline at end of file +#endif From 4804b1c165d38b5163376d94f19bc35d88681897 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Thu, 20 Nov 2025 15:16:43 +0100 Subject: [PATCH 026/234] Common: EnumFlags add set --- Common/Utils/include/CommonUtils/EnumFlags.h | 148 +++++--- Common/Utils/test/testEnumFlags.cxx | 345 +++++++++++++++++++ 2 files changed, 449 insertions(+), 44 deletions(-) diff --git a/Common/Utils/include/CommonUtils/EnumFlags.h b/Common/Utils/include/CommonUtils/EnumFlags.h index 4bd1a9e641056..e7481c903e666 100644 --- a/Common/Utils/include/CommonUtils/EnumFlags.h +++ b/Common/Utils/include/CommonUtils/EnumFlags.h @@ -54,10 +54,12 @@ concept EnumFlagHelper = requires { // functions and also check via concepts expected properties of the enum. // This is very much inspired by much more extensive libraries like magic_enum. // Inspiration by its c++20 version (https://github.com/fix8mt/conjure_enum). +// NOTE: Cannot detect if bit values past the underlying type are defined. template struct FlagsHelper final { using U = std::underlying_type_t; using UMax = uint64_t; // max represetable type + static_assert(std::numeric_limits::digits <= std::numeric_limits::digits, "Underlying type has more digits than max supported digits"); static constexpr bool isScoped() noexcept { @@ -108,7 +110,7 @@ struct FlagsHelper final { static constexpr size_t MaxUnderScan{std::numeric_limits::digits}; // Maximum digits the underlying type has static constexpr size_t MaxScan{MaxUnderScan + MarginScan}; - // Checks if a given 'localation' contains an enum. + // Checks if a given 'location' contains an enum. template static constexpr bool isValid() noexcept { @@ -128,14 +130,14 @@ struct FlagsHelper final { // check if this is an anonymous enum return true; } - return false; -#else +#elif __GNUC__ else if constexpr (tpeek_v[tp + getSpec().size()] != '(' && tpeek_v.find_first_of(getSpec(), tp + getSpec().size()) != std::string_view::npos) { return true; - } else { - return false; } +#else +#error Unsupported compiler #endif + return false; } // Extract which values are present in the enum by checking all values in @@ -161,7 +163,7 @@ struct FlagsHelper final { static constexpr auto Max_v{Values.back()}; // Enum last entry static constexpr auto Min_u_v{static_cast(Min_v)}; // Enum first entry as size_t static constexpr auto Max_u_v{static_cast(Max_v)}; // Enum last entry as size_t - static_assert(Max_u_v < std::numeric_limits::digits, "Max Bit is beyond allow range defered from underlying type"); + static_assert(Max_u_v < std::numeric_limits::digits, "Max Bit is beyond allow range deferred from underlying type"); static constexpr bool isContinuous() noexcept { return (Max_u_v - Min_u_v + 1) == count(); } // Is the enum continuous static constexpr UMax makeMaxRep(size_t min, size_t max) { @@ -258,7 +260,7 @@ struct FlagsHelper final { static constexpr std::optional fromString(std::string_view str) noexcept { for (size_t i{0}; i < count(); ++i) { - if (Names[i] == str || NamesScoped[i] == str) { + if (isIEqual(Names[i], str) || isIEqual(NamesScoped[i], str)) { return Values[i]; } } @@ -277,7 +279,7 @@ struct FlagsHelper final { return toLower(a) == toLower(b); } - // Case-insensitive comparision for string_view. + // Case-insensitive comparison for string_view. static constexpr bool isIEqual(std::string_view s1, std::string_view s2) noexcept { if (s1.size() != s2.size()) { @@ -294,7 +296,7 @@ struct FlagsHelper final { static constexpr std::string_view None{"none"}; static constexpr bool hasNone() noexcept { - // check that enum does not contain memeber named 'none' + // check that enum does not contain member named 'none' for (size_t i{0}; i < count(); ++i) { if (isIEqual(Names[i], None)) { return true; @@ -306,7 +308,7 @@ struct FlagsHelper final { static constexpr std::string_view All{"all"}; static constexpr bool hasAll() noexcept { - // check that enum does not contain memeber named 'all' + // check that enum does not contain member named 'all' for (size_t i{0}; i < count(); ++i) { if (isIEqual(Names[i], All)) { return true; @@ -332,7 +334,7 @@ concept EnumFlag = requires { }; /** - * \brief Classs to aggregate and manage enum-based on-off flags. + * \brief Class to aggregate and manage enum-based on-off flags. * * This class manages flags as bits in the underlying type of an enum (upto 64 bits), allowing * manipulation via enum member names. It supports operations akin to std::bitset @@ -355,6 +357,7 @@ concept EnumFlag = requires { template class EnumFlags { + static constexpr int DefaultBase{2}; using H = details::enum_flags::FlagsHelper; using U = std::underlying_type_t; U mBits{0}; @@ -388,9 +391,10 @@ class EnumFlags std::for_each(flags.begin(), flags.end(), [this](const E f) noexcept { mBits |= to_bit(f); }); } // Init from a string. - EnumFlags(const std::string& str) + // + explicit EnumFlags(const std::string& str, int base = DefaultBase) { - set(str); + set(str, base); } // Destructor. constexpr ~EnumFlags() = default; @@ -413,14 +417,14 @@ class EnumFlags // Sets flags from a string representation. // This can be either from a number representation (binary or digits) or // a concatenation of the enums members name e.g., 'Enum1|Enum2|...' - void set(const std::string& s = "", int base = 2) + void set(const std::string& s, int base = DefaultBase) { - // on throw restore previous state and rethrow - const U prev = mBits; - reset(); if (s.empty()) { // no-op return; } + // on throw restore previous state and rethrow + const U prev = mBits; + reset(); try { setImpl(s, base); } catch (const std::exception& e) { @@ -441,39 +445,42 @@ class EnumFlags } // Resets a specific flag. - template - requires std::is_same_v + template T> constexpr void reset(T t) { mBits &= ~to_bit(t); } // Tests if a specific flag is set. - template - requires std::is_same_v + template T> [[nodiscard]] constexpr bool test(T t) const noexcept { return (mBits & to_bit(t)) != None; } // Tests if all specified flags are set. - template + template ... Ts> [[nodiscard]] constexpr bool test(Ts... flags) const noexcept { return ((test(flags) && ...)); } // Sets a specific flag. - template - requires std::is_same_v + template T> constexpr void set(T t) noexcept { mBits |= to_bit(t); } + // Sets multiple specific flags. + template ... Ts> + constexpr void set(Ts... flags) noexcept + { + (set(flags), ...); + } + // Toggles a specific flag. - template - requires std::is_same_v + template T> constexpr void toggle(T t) noexcept { mBits ^= to_bit(t); @@ -538,8 +545,7 @@ class EnumFlags } // Check if given flag is set. - template - requires std::is_same_v + template T> [[nodiscard]] constexpr bool operator[](const T t) const noexcept { return test(t); @@ -564,8 +570,7 @@ class EnumFlags constexpr EnumFlags& operator=(EnumFlags&& o) = default; // Performs a bitwise OR with a flag. - template - requires std::is_same_v + template T> constexpr EnumFlags& operator|=(T t) noexcept { mBits |= to_bit(t); @@ -573,8 +578,7 @@ class EnumFlags } // Performs a bitwise AND with a flag. - template - requires std::is_same_v + template T> constexpr EnumFlags& operator&=(T t) noexcept { mBits &= to_bit(t); @@ -582,8 +586,7 @@ class EnumFlags } // Returns a flag set with a bitwise AND. - template - requires std::is_same_v + template T> constexpr EnumFlags operator&(T t) const noexcept { return EnumFlags(mBits & to_bit(t)); @@ -685,32 +688,89 @@ class EnumFlags // Set implementation, bits was zeroed before. void setImpl(const std::string& s, int base = 2) { + // Helper to check if character is valid for given base + auto isValidForBase = [](unsigned char c, int base) -> bool { + if (base == 2) { + return c == '0' || c == '1'; + } + if (base == 10) { + return std::isdigit(c); + } + if (base == 16) { + return std::isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); + } + return false; + }; + + // hex + if (base == 16) { + std::string_view hex_str{s}; + // Strip optional 0x or 0X prefix + if (s.size() >= 2 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { + hex_str.remove_prefix(2); + } + if (hex_str.empty()) { + throw std::invalid_argument("Empty hexadecimal string."); + } + if (!std::all_of(hex_str.begin(), hex_str.end(), [&](unsigned char c) { return isValidForBase(c, 16); })) { + throw std::invalid_argument("Invalid hexadecimal string."); + } + typename H::UMax v = std::stoul(std::string(hex_str), nullptr, 16); + if (v > H::MaxRep) { + throw std::out_of_range("Value exceeds enum range."); + } + mBits = static_cast(v); + return; + } + + // decimal and binary if (std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isdigit(c); })) { - if (base == 2) { // check of only 0 and 1 in string - if (!std::all_of(s.begin(), s.end(), [](char c) { return c == '0' || c == '1'; })) { + if (base == 2) { + // Binary: check only 0 and 1 + if (!std::all_of(s.begin(), s.end(), [&](unsigned char c) { return isValidForBase(c, 2); })) { throw std::invalid_argument("Invalid binary string."); } } - typename H::UMax v = std::stoul(s, nullptr, base); + typename H::UMax v = std::stoul(std::string(s), nullptr, base); if (v > H::MaxRep) { - throw std::out_of_range("Values exceeds enum range."); + throw std::out_of_range("Value exceeds enum range."); } mBits = static_cast(v); - } else if (std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isalnum(c) != 0 || c == '|' || c == ' ' || c == ':' || c == ',' || c == ';'; })) { + } + // enum name strings + else if (std::all_of(s.begin(), s.end(), [](unsigned char c) { return std::isalnum(c) != 0 || c == '|' || c == ' ' || c == ':' || c == ',' || c == ';'; })) { std::string cs{s}; std::transform(cs.begin(), cs.end(), cs.begin(), [](unsigned char c) { return std::tolower(c); }); + if (cs == H::All) { mBits = All; } else if (cs == H::None) { mBits = None; } else { - // accept as delimiter ' ', '|', ';', ',' + // Detect delimiter and ensure only one type is used char token = ' '; - std::string::size_type pos = s.find_first_of(",|;"); - if (pos != std::string::npos) { - token = s[pos]; + size_t pipePos = s.find('|'); + size_t commaPos = s.find(','); + size_t semiPos = s.find(';'); + + // Count how many different delimiters exist + int delimiterCount = (pipePos != std::string_view::npos ? 1 : 0) + + (commaPos != std::string_view::npos ? 1 : 0) + + (semiPos != std::string_view::npos ? 1 : 0); + + if (delimiterCount > 1) { + throw std::invalid_argument("Mixed delimiters not allowed!"); + } + + if (pipePos != std::string_view::npos) { + token = '|'; + } else if (commaPos != std::string_view::npos) { + token = ','; + } else if (semiPos != std::string_view::npos) { + token = ';'; } - for (const auto& tok : Str::tokenize(s, token)) { + + for (const auto& tok : Str::tokenize(std::string(s), token)) { if (auto e = H::fromString(tok)) { mBits |= to_bit(*e); } else { diff --git a/Common/Utils/test/testEnumFlags.cxx b/Common/Utils/test/testEnumFlags.cxx index 80f85c847653b..9101ffb97fdfe 100644 --- a/Common/Utils/test/testEnumFlags.cxx +++ b/Common/Utils/test/testEnumFlags.cxx @@ -74,11 +74,22 @@ BOOST_AUTO_TEST_CASE(Flags_test) multipleFlags.reset(); BOOST_TEST(!multipleFlags.any()); + // Test multiset + multipleFlags.reset(); + multipleFlags.set(TestEnum::Bit2, TestEnum::Bit4); + BOOST_TEST(!multipleFlags.test(TestEnum::Bit1)); + BOOST_TEST(multipleFlags.test(TestEnum::Bit2)); + BOOST_TEST(!multipleFlags.test(TestEnum::Bit3)); + BOOST_TEST(multipleFlags.test(TestEnum::Bit4)); + BOOST_TEST(!multipleFlags.test(TestEnum::Bit5VeryLongName)); + // Test operator| EFlags combinedFlags = flag1 | EFlags(TestEnum::Bit2); BOOST_TEST(combinedFlags.test(TestEnum::Bit1)); BOOST_TEST(combinedFlags.test(TestEnum::Bit2)); BOOST_TEST(!combinedFlags.test(TestEnum::Bit3)); + combinedFlags |= TestEnum::Bit5VeryLongName; + BOOST_TEST(combinedFlags.test(TestEnum::Bit5VeryLongName)); // Test operator[] BOOST_TEST(combinedFlags[TestEnum::Bit1]); @@ -306,3 +317,337 @@ BOOST_AUTO_TEST_CASE(Flags_test) BOOST_CHECK(!test.test(TestEnumLong::Bit1, TestEnumLong::Bit23)); } } + +BOOST_AUTO_TEST_CASE(Flags_case_insensitive_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test case-insensitive flag names + { + EFlags flags("bit1"); // lowercase + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(!flags.test(TestEnum::Bit2)); + } + + { + EFlags flags("BIT2"); // uppercase + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(!flags.test(TestEnum::Bit1)); + } + + { + EFlags flags("BiT3"); // mixed case + BOOST_CHECK(flags.test(TestEnum::Bit3)); + } + + { + EFlags flags("bit1|BIT2|BiT3"); // mixed case with delimiter + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + } + + // Test special keywords case-insensitive + { + EFlags flags("ALL"); + BOOST_CHECK(flags.all()); + } + + { + EFlags flags("None"); + BOOST_CHECK(!flags.any()); + } +} + +BOOST_AUTO_TEST_CASE(Flags_error_recovery_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test that previous state is restored on exception + { + EFlags flags({TestEnum::Bit1, TestEnum::Bit2}); + auto previousValue = flags.value(); + + // Try to set with invalid string + BOOST_CHECK_THROW(flags.set("InvalidFlag"), std::invalid_argument); + + // Verify state was restored + BOOST_CHECK_EQUAL(flags.value(), previousValue); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + } + + { + EFlags flags({TestEnum::Bit3, TestEnum::Bit4}); + auto previousValue = flags.value(); + + // Try to set with out-of-range value + BOOST_CHECK_THROW(flags.set("999999", 10), std::out_of_range); + + // Verify state was restored + BOOST_CHECK_EQUAL(flags.value(), previousValue); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + BOOST_CHECK(flags.test(TestEnum::Bit4)); + } + + { + EFlags flags(TestEnum::Bit5VeryLongName); + auto previousValue = flags.value(); + + // Try to set with invalid binary string + BOOST_CHECK_THROW(flags.set("10102", 2), std::invalid_argument); + + // Verify state was restored + BOOST_CHECK_EQUAL(flags.value(), previousValue); + BOOST_CHECK(flags.test(TestEnum::Bit5VeryLongName)); + } +} + +BOOST_AUTO_TEST_CASE(Flags_whitespace_handling_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test leading/trailing whitespace + { + EFlags flags(" Bit1 "); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + } + + { + EFlags flags(" Bit1 | Bit2 "); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + } + + // Test excessive whitespace between flags + { + EFlags flags("Bit1 | Bit3"); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + BOOST_CHECK(!flags.test(TestEnum::Bit2)); + } + + // Test tabs and other whitespace (should work with space delimiter) + { + EFlags flags("Bit1 Bit2 Bit3"); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + } +} + +BOOST_AUTO_TEST_CASE(Flags_count_bits_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test counting set bits + { + EFlags flags; + BOOST_CHECK_EQUAL(flags.count(), 0); + } + + { + EFlags flags(TestEnum::Bit1); + BOOST_CHECK_EQUAL(flags.count(), 1); + } + + { + EFlags flags({TestEnum::Bit1, TestEnum::Bit2}); + BOOST_CHECK_EQUAL(flags.count(), 2); + } + + { + EFlags flags({TestEnum::Bit1, TestEnum::Bit2, TestEnum::Bit3, TestEnum::Bit4}); + BOOST_CHECK_EQUAL(flags.count(), 4); + } + + { + EFlags flags(EFlags::All); + BOOST_CHECK_EQUAL(flags.count(), 5); // TestEnum has 5 members + } + + // Test count after operations + { + EFlags flags({TestEnum::Bit1, TestEnum::Bit2, TestEnum::Bit3}); + BOOST_CHECK_EQUAL(flags.count(), 3); + + flags.reset(TestEnum::Bit2); + BOOST_CHECK_EQUAL(flags.count(), 2); + + flags.set(TestEnum::Bit4); + BOOST_CHECK_EQUAL(flags.count(), 3); + + flags.toggle(TestEnum::Bit1); + BOOST_CHECK_EQUAL(flags.count(), 2); + } +} + +BOOST_AUTO_TEST_CASE(Flags_mixed_delimiter_validation_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test that mixed delimiters throw an error + { + BOOST_CHECK_THROW(EFlags("Bit1|Bit2,Bit3"), std::invalid_argument); + } + + { + BOOST_CHECK_THROW(EFlags("Bit1;Bit2|Bit3"), std::invalid_argument); + } + + { + BOOST_CHECK_THROW(EFlags("Bit1,Bit2;Bit3"), std::invalid_argument); + } + + { + BOOST_CHECK_THROW(EFlags("Bit1|Bit2,Bit3;Bit4"), std::invalid_argument); + } + + // Test that single delimiter types work + { + EFlags flags1("Bit1|Bit2|Bit3"); + BOOST_CHECK_EQUAL(flags1.count(), 3); + } + + { + EFlags flags2("Bit1,Bit2,Bit3"); + BOOST_CHECK_EQUAL(flags2.count(), 3); + } + + { + EFlags flags3("Bit1;Bit2;Bit3"); + BOOST_CHECK_EQUAL(flags3.count(), 3); + } +} + +BOOST_AUTO_TEST_CASE(Flags_empty_and_edge_cases_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test empty string + { + EFlags flags({TestEnum::Bit1, TestEnum::Bit2}); + flags.set(""); // Should be no-op + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + } + + // Test with only whitespace + { + EFlags flags({TestEnum::Bit1}); + flags.set(" "); // Should result in empty after tokenization + // Depending on implementation, this might clear or throw + // Adjust expectation based on actual behavior + } + + // Test duplicate flags (should work, setting same bit twice is idempotent) + { + EFlags flags("Bit1|Bit1|Bit1"); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK_EQUAL(flags.count(), 1); + } + + // Test scoped and unscoped mixed + { + EFlags flags("Bit1|TestEnum::Bit2"); + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + } +} + +BOOST_AUTO_TEST_CASE(Flags_binary_decimal_parsing_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test binary parsing + { + EFlags flags("101", 2); + BOOST_CHECK(flags.test(TestEnum::Bit1)); // bit 0 + BOOST_CHECK(!flags.test(TestEnum::Bit2)); // bit 1 + BOOST_CHECK(flags.test(TestEnum::Bit3)); // bit 2 + } + + // Test decimal parsing + { + EFlags flags("7", 10); // 7 = 0b111 + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + BOOST_CHECK(!flags.test(TestEnum::Bit4)); + } + + // Test hexadecimal parsing + { + EFlags flags("F", 16); // 15 = 0b1111 + BOOST_CHECK(flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(flags.test(TestEnum::Bit3)); + BOOST_CHECK(flags.test(TestEnum::Bit4)); + BOOST_CHECK(!flags.test(TestEnum::Bit5VeryLongName)); + } + + // Test hexadecimal with 0x prefix + { + EFlags flags("0xA", 16); // 10 = 0b1010 + BOOST_CHECK(!flags.test(TestEnum::Bit1)); + BOOST_CHECK(flags.test(TestEnum::Bit2)); + BOOST_CHECK(!flags.test(TestEnum::Bit3)); + BOOST_CHECK(flags.test(TestEnum::Bit4)); + } + + // Test hexadecimal with 0X prefix (uppercase) + { + EFlags flags("0X1F", 16); // 31 = all 5 bits + BOOST_CHECK(flags.all()); + } + + // Test lowercase hex digits + { + EFlags flags("0xa", 16); + BOOST_CHECK_EQUAL(flags.value(), 10); + } + + // Test thros + { + BOOST_CHECK_THROW(EFlags("0xAbCd", 16), std::out_of_range); + } + + // Test invalid binary string (contains 2) + { + BOOST_CHECK_THROW(EFlags("1012", 2), std::invalid_argument); + } + + // Test out of range for base + { + BOOST_CHECK_THROW(EFlags("100000", 2), std::out_of_range); + } +} + +BOOST_AUTO_TEST_CASE(Flags_operator_bool_test) +{ + using EFlags = o2::utils::EnumFlags; + + // Test explicit bool conversion + { + EFlags empty; + BOOST_CHECK(!static_cast(empty)); + } + + { + EFlags withFlag(TestEnum::Bit1); + BOOST_CHECK(static_cast(withFlag)); + } + + // Test in conditional + { + EFlags flags; + if (flags) { + BOOST_FAIL("Empty flags should be false"); + } + + flags.set(TestEnum::Bit1); + if (!flags) { + BOOST_FAIL("Non-empty flags should be true"); + } + } +} From 73c5a52720543e6405c8e6dd9e1ffa70c645d508 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 22 Dec 2025 21:06:16 +0100 Subject: [PATCH 027/234] DCA Fitter GPU: Disable failing test, which was not active before and seems broken --- Common/DCAFitter/GPU/cuda/CMakeLists.txt | 22 +++++++++++----------- Common/DCAFitter/GPU/hip/CMakeLists.txt | 24 ++++++++++++------------ GPU/Common/CMakeLists.txt | 20 ++++++++++---------- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/Common/DCAFitter/GPU/cuda/CMakeLists.txt b/Common/DCAFitter/GPU/cuda/CMakeLists.txt index ddc1d09445d7f..6b89207279fe0 100644 --- a/Common/DCAFitter/GPU/cuda/CMakeLists.txt +++ b/Common/DCAFitter/GPU/cuda/CMakeLists.txt @@ -22,14 +22,14 @@ o2_add_library(DCAFitterCUDA set_property(TARGET ${targetName} PROPERTY CUDA_SEPARABLE_COMPILATION ON) # add_compile_options(-lineinfo) -o2_add_test(DCAFitterNCUDA - SOURCES test/testDCAFitterNGPU.cxx - PUBLIC_LINK_LIBRARIES O2::ReconstructionDataFormats - O2::DCAFitterCUDA - O2::DCAFitter - ROOT::Core - ROOT::Physics - COMPONENT_NAME gpu - LABELS vertexing - ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage - VMCWORKDIR=${CMAKE_BINARY_DIR}/stage/${CMAKE_INSTALL_DATADIR}) \ No newline at end of file +#o2_add_test(DCAFitterNCUDA +# SOURCES test/testDCAFitterNGPU.cxx +# PUBLIC_LINK_LIBRARIES O2::ReconstructionDataFormats +# O2::DCAFitterCUDA +# O2::DCAFitter +# ROOT::Core +# ROOT::Physics +# COMPONENT_NAME gpu +# LABELS vertexing +# ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage +# VMCWORKDIR=${CMAKE_BINARY_DIR}/stage/${CMAKE_INSTALL_DATADIR}) diff --git a/Common/DCAFitter/GPU/hip/CMakeLists.txt b/Common/DCAFitter/GPU/hip/CMakeLists.txt index f62759bb6ea2c..5e7821a0b8946 100644 --- a/Common/DCAFitter/GPU/hip/CMakeLists.txt +++ b/Common/DCAFitter/GPU/hip/CMakeLists.txt @@ -21,15 +21,15 @@ o2_add_hipified_library(DCAFitterHIP PRIVATE_LINK_LIBRARIES O2::GPUTrackingHIPExternalProvider TARGETVARNAME targetNAme) -o2_add_test(DCAFitterNHIP - SOURCES ../cuda/test/testDCAFitterNGPU.cxx - PUBLIC_LINK_LIBRARIES O2::ReconstructionDataFormats - O2::DCAFitterHIP - O2::DCAFitter - ROOT::Core - ROOT::Physics - HIPIFIED test - COMPONENT_NAME gpu - LABELS vertexing - ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage - VMCWORKDIR=${CMAKE_BINARY_DIR}/stage/${CMAKE_INSTALL_DATADIR}) \ No newline at end of file +#o2_add_test(DCAFitterNHIP +# SOURCES ../cuda/test/testDCAFitterNGPU.cxx +# PUBLIC_LINK_LIBRARIES O2::ReconstructionDataFormats +# O2::DCAFitterHIP +# O2::DCAFitter +# ROOT::Core +# ROOT::Physics +# HIPIFIED test +# COMPONENT_NAME gpu +# LABELS vertexing +# ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage +# VMCWORKDIR=${CMAKE_BINARY_DIR}/stage/${CMAKE_INSTALL_DATADIR}) diff --git a/GPU/Common/CMakeLists.txt b/GPU/Common/CMakeLists.txt index b1a4b2107019c..8f7a7c2e169ed 100644 --- a/GPU/Common/CMakeLists.txt +++ b/GPU/Common/CMakeLists.txt @@ -52,16 +52,16 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2") COMPONENT_NAME GPU LABELS gpu) endif() - if (HIP_ENABLED) - o2_add_test(SMatrixImpHIP NAME test_SMatrixImpHIP - SOURCES test/testSMatrixImp.cu - HIPIFIED test - PUBLIC_LINK_LIBRARIES O2::${MODULE} - O2::MathUtils - ROOT::Core - COMPONENT_NAME GPU - LABELS gpu) - endif() +# if (HIP_ENABLED) +# o2_add_test(SMatrixImpHIP NAME test_SMatrixImpHIP +# SOURCES test/testSMatrixImp.cu +# HIPIFIED test +# PUBLIC_LINK_LIBRARIES O2::${MODULE} +# O2::MathUtils +# ROOT::Core +# COMPONENT_NAME GPU +# LABELS gpu) +# endif() endif() install(FILES ${HDRS_INSTALL} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/GPU) From bfcff02b88be6053c154e385acefd235dfed69d4 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 24 Dec 2025 23:16:32 +0100 Subject: [PATCH 028/234] Fix some codechecker violations (#14936) --- .../CPV/reconstruction/include/CPVReconstruction/CTFCoder.h | 2 +- .../CTP/reconstruction/include/CTPReconstruction/CTFCoder.h | 2 +- .../reconstruction/include/EMCALReconstruction/CTFCoder.h | 2 +- .../FDD/reconstruction/include/FDDReconstruction/CTFCoder.h | 2 +- .../FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h | 2 +- .../FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h | 2 +- Detectors/GlobalTrackingWorkflow/study/src/DumpTracks.cxx | 2 +- Detectors/GlobalTrackingWorkflow/study/src/SVStudy.cxx | 2 +- Detectors/GlobalTrackingWorkflow/study/src/TPCTrackStudy.cxx | 2 +- Detectors/GlobalTrackingWorkflow/study/src/TrackMCStudy.cxx | 2 +- Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx | 4 ++-- .../reconstruction/include/HMPIDReconstruction/CTFCoder.h | 2 +- .../ITS/QC/TestDataReaderWorkflow/src/TestDataReader.cxx | 1 - .../reconstruction/include/ITSMFTReconstruction/CTFCoder.h | 2 +- Detectors/MUON/MCH/CTF/include/MCHCTF/CTFCoder.h | 2 +- Detectors/MUON/MID/CTF/include/MIDCTF/CTFCoder.h | 2 +- .../PHOS/reconstruction/include/PHOSReconstruction/CTFCoder.h | 2 +- .../TOF/reconstruction/include/TOFReconstruction/CTFCoder.h | 2 +- .../TPC/reconstruction/include/TPCReconstruction/CTFCoder.h | 2 +- .../TRD/reconstruction/include/TRDReconstruction/CTFCoder.h | 2 +- .../ZDC/reconstruction/include/ZDCReconstruction/CTFCoder.h | 2 +- Framework/Utils/include/DPLUtils/RootTreeWriter.h | 2 +- 22 files changed, 22 insertions(+), 23 deletions(-) diff --git a/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFCoder.h b/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFCoder.h index e9bd0f7249ef1..ab5082b5c748c 100644 --- a/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFCoder.h +++ b/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFCoder.h @@ -32,7 +32,7 @@ namespace o2 namespace cpv { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::CPV) {} diff --git a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h index 9189df5d12685..87657f6a6f8c6 100644 --- a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h +++ b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h @@ -34,7 +34,7 @@ namespace o2 namespace ctp { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::CTP) {} diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h index 1617a9f1a7d54..23deb75ffb049 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h @@ -32,7 +32,7 @@ namespace o2 namespace emcal { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::EMC) {} diff --git a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/CTFCoder.h b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/CTFCoder.h index dc11174908c75..94a0c6f64659d 100644 --- a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/CTFCoder.h +++ b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/CTFCoder.h @@ -33,7 +33,7 @@ namespace o2 namespace fdd { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::FDD) {} diff --git a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h index 4d749dbc90b42..65646c161dde5 100644 --- a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h +++ b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h @@ -34,7 +34,7 @@ namespace o2 namespace ft0 { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::FT0) {} diff --git a/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h b/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h index cbec444ef11be..4398e19c0a5ed 100644 --- a/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h +++ b/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h @@ -30,7 +30,7 @@ namespace o2 namespace fv0 { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::FV0) {} diff --git a/Detectors/GlobalTrackingWorkflow/study/src/DumpTracks.cxx b/Detectors/GlobalTrackingWorkflow/study/src/DumpTracks.cxx index dbf34b8eb14ad..d02f1df3903ec 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/DumpTracks.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/DumpTracks.cxx @@ -48,7 +48,7 @@ using TBracket = o2::math_utils::Bracketf_t; using timeEst = o2::dataformats::TimeStampWithError; -class DumpTracksSpec : public Task +class DumpTracksSpec final : public Task { public: DumpTracksSpec(std::shared_ptr dr, std::shared_ptr gr, GTrackID::mask_t src, bool useMC) diff --git a/Detectors/GlobalTrackingWorkflow/study/src/SVStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/SVStudy.cxx index 1e141a29d3f55..0129d19b02346 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/SVStudy.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/SVStudy.cxx @@ -68,7 +68,7 @@ using V0ID = o2::dataformats::V0Index; using timeEst = o2::dataformats::TimeStampWithError; -class SVStudySpec : public Task +class SVStudySpec final : public Task { public: SVStudySpec(std::shared_ptr dr, std::shared_ptr gr, GTrackID::mask_t src, bool useTPCCl, bool useMC) diff --git a/Detectors/GlobalTrackingWorkflow/study/src/TPCTrackStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/TPCTrackStudy.cxx index 09ef766aa1536..05e6a122adec9 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/TPCTrackStudy.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/TPCTrackStudy.cxx @@ -47,7 +47,7 @@ using TBracket = o2::math_utils::Bracketf_t; using timeEst = o2::dataformats::TimeStampWithError; -class TPCTrackStudySpec : public Task +class TPCTrackStudySpec final : public Task { public: TPCTrackStudySpec(std::shared_ptr dr, std::shared_ptr gr, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, GTrackID::mask_t src, bool useMC) diff --git a/Detectors/GlobalTrackingWorkflow/study/src/TrackMCStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/TrackMCStudy.cxx index c4a0a30116557..8f6604b029605 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/TrackMCStudy.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/TrackMCStudy.cxx @@ -83,7 +83,7 @@ using TBracket = o2::math_utils::Bracketf_t; using timeEst = o2::dataformats::TimeStampWithError; -class TrackMCStudy : public Task +class TrackMCStudy final : public Task { public: TrackMCStudy(std::shared_ptr dr, std::shared_ptr gr, GTrackID::mask_t src, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, bool checkSV) diff --git a/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx index 531ee03290201..b8a8f97737b4d 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx @@ -67,7 +67,7 @@ using TBracket = o2::math_utils::Bracketf_t; using timeEst = o2::dataformats::TimeStampWithError; -class TrackingStudySpec : public Task +class TrackingStudySpec final : public Task { public: TrackingStudySpec(std::shared_ptr dr, std::shared_ptr gr, GTrackID::mask_t src, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts) @@ -444,7 +444,7 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) } bool ambig = vid.isAmbiguous(); auto trc = recoData.getTrackParam(vid); - if (abs(trc.getEta()) > mMaxEta) { + if (fabs(trc.getEta()) > mMaxEta) { continue; } if (iv < nv - 1 && is == GTrackID::TPC && tpcTr && !tpcTr->hasBothSidesClusters()) { // for unconstrained TPC tracks correct track Z diff --git a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFCoder.h b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFCoder.h index da2461c2759ba..39242355a3de9 100644 --- a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFCoder.h +++ b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFCoder.h @@ -32,7 +32,7 @@ namespace o2 namespace hmpid { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::HMP) {} diff --git a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataReader.cxx b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataReader.cxx index 1fc4442e3bdbf..90ed033ed67da 100644 --- a/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataReader.cxx +++ b/Detectors/ITSMFT/ITS/QC/TestDataReaderWorkflow/src/TestDataReader.cxx @@ -509,7 +509,6 @@ void TestDataReader::run(ProcessingContext& pc) std::vector TestDataReader::GetFName(std::string folder) { - DIR* dirp; char cstr[folder.size() + 1]; diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/CTFCoder.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/CTFCoder.h index 2d4aabc94fc82..94c14424f6ce3 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/CTFCoder.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/CTFCoder.h @@ -39,7 +39,7 @@ namespace o2 namespace itsmft { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: using PMatrix = std::array, ClusterPattern::MaxColSpan + 2>; diff --git a/Detectors/MUON/MCH/CTF/include/MCHCTF/CTFCoder.h b/Detectors/MUON/MCH/CTF/include/MCHCTF/CTFCoder.h index fc090c5c7e16d..2d65cbbaea614 100644 --- a/Detectors/MUON/MCH/CTF/include/MCHCTF/CTFCoder.h +++ b/Detectors/MUON/MCH/CTF/include/MCHCTF/CTFCoder.h @@ -34,7 +34,7 @@ namespace o2 namespace mch { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::MCH) {} diff --git a/Detectors/MUON/MID/CTF/include/MIDCTF/CTFCoder.h b/Detectors/MUON/MID/CTF/include/MIDCTF/CTFCoder.h index 3071b65db47b1..5afc42550ae3e 100644 --- a/Detectors/MUON/MID/CTF/include/MIDCTF/CTFCoder.h +++ b/Detectors/MUON/MID/CTF/include/MIDCTF/CTFCoder.h @@ -34,7 +34,7 @@ namespace o2 namespace mid { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::MID) {} diff --git a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CTFCoder.h b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CTFCoder.h index 96ee5093bacca..8a7172f634a33 100644 --- a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CTFCoder.h +++ b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CTFCoder.h @@ -32,7 +32,7 @@ namespace o2 namespace phos { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::PHS) {} diff --git a/Detectors/TOF/reconstruction/include/TOFReconstruction/CTFCoder.h b/Detectors/TOF/reconstruction/include/TOFReconstruction/CTFCoder.h index e559dcce7a1da..e7a203cfcb25e 100644 --- a/Detectors/TOF/reconstruction/include/TOFReconstruction/CTFCoder.h +++ b/Detectors/TOF/reconstruction/include/TOFReconstruction/CTFCoder.h @@ -31,7 +31,7 @@ namespace o2 namespace tof { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::TOF) {} diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/CTFCoder.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/CTFCoder.h index ab49d0d49d79b..12d66ef6a6e7c 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/CTFCoder.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/CTFCoder.h @@ -119,7 +119,7 @@ struct MergedColumnsDecoder { } // namespace detail -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::TPC) {} diff --git a/Detectors/TRD/reconstruction/include/TRDReconstruction/CTFCoder.h b/Detectors/TRD/reconstruction/include/TRDReconstruction/CTFCoder.h index 27e089fcf3555..9eeaf19db5025 100644 --- a/Detectors/TRD/reconstruction/include/TRDReconstruction/CTFCoder.h +++ b/Detectors/TRD/reconstruction/include/TRDReconstruction/CTFCoder.h @@ -33,7 +33,7 @@ namespace o2 namespace trd { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::TRD) {} diff --git a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFCoder.h b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFCoder.h index c2f2163600f29..f8823e4fc66a5 100644 --- a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFCoder.h +++ b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFCoder.h @@ -32,7 +32,7 @@ namespace o2 namespace zdc { -class CTFCoder : public o2::ctf::CTFCoderBase +class CTFCoder final : public o2::ctf::CTFCoderBase { public: CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::ZDC) {} diff --git a/Framework/Utils/include/DPLUtils/RootTreeWriter.h b/Framework/Utils/include/DPLUtils/RootTreeWriter.h index 0161c67396543..b937a83f5972a 100644 --- a/Framework/Utils/include/DPLUtils/RootTreeWriter.h +++ b/Framework/Utils/include/DPLUtils/RootTreeWriter.h @@ -714,7 +714,7 @@ class RootTreeWriter impl.start = &(data[0]); impl.end = &(data[data.size() - 1]) + 1; // end pointer (beyond last element) impl.cap = impl.end; - std::memcpy(&v, &impl, sizeof(VecBase)); + std::memcpy((void*)&v, (const void*)&impl, sizeof(VecBase)); }; // if the value type is messagable and has a ROOT dictionary, two serialization methods are possible From 89cebea4fdb75bb6bf85a9f5d33cb021a3093cb4 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 25 Dec 2025 18:44:28 +0100 Subject: [PATCH 029/234] GPU: Support virtual and real architectures in RTC --- GPU/GPUTracking/Base/cuda/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/GPU/GPUTracking/Base/cuda/CMakeLists.txt b/GPU/GPUTracking/Base/cuda/CMakeLists.txt index 7f595b28a582a..e7a579bec794d 100644 --- a/GPU/GPUTracking/Base/cuda/CMakeLists.txt +++ b/GPU/GPUTracking/Base/cuda/CMakeLists.txt @@ -41,9 +41,11 @@ set(GPU_RTC_FLAGS "${CMAKE_CUDA_FLAGS} ${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE_UPP set(GPU_RTC_FLAGS_ARCH "") if(CUDA_COMPUTETARGET) foreach(CUDA_ARCH ${CUDA_COMPUTETARGET}) - set(GPU_RTC_FLAGS_ARCH "${GPU_RTC_FLAGS_ARCH} -gencode arch=compute_${CUDA_ARCH},code=sm_${CUDA_ARCH}") + string(REGEX REPLACE "-.*$" "" CUDA_ARCH_STRIPPED "${CUDA_ARCH}") + set(GPU_RTC_FLAGS_ARCH "${GPU_RTC_FLAGS_ARCH} -gencode arch=compute_${CUDA_ARCH_STRIPPED},code=sm_${CUDA_ARCH_STRIPPED}") endforeach() list (GET CUDA_COMPUTETARGET 0 RTC_CUDA_ARCH) + string(REGEX REPLACE "-.*$" "" RTC_CUDA_ARCH "${RTC_CUDA_ARCH}") set(RTC_CUDA_ARCH "${RTC_CUDA_ARCH}0") else() set(RTC_CUDA_ARCH "750") From 0bc34efd29e2b0cc4dade68f538da91046d4ae48 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 25 Dec 2025 16:02:08 +0100 Subject: [PATCH 030/234] GPU: Change default CUDA architectures to 80-real 86-real 89-real 120-real 75-virtual --- dependencies/FindO2GPU.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies/FindO2GPU.cmake b/dependencies/FindO2GPU.cmake index 0be3448ed6fce..6ca311905e01c 100644 --- a/dependencies/FindO2GPU.cmake +++ b/dependencies/FindO2GPU.cmake @@ -10,7 +10,7 @@ # or submit itself to any jurisdiction. # NOTE!!!! - Whenever this file is changed, move it over to alidist/resources -# FindO2GPU.cmake Version 7 +# FindO2GPU.cmake Version 8 if(NOT DEFINED ENABLE_CUDA) set(ENABLE_CUDA "AUTO") @@ -32,7 +32,7 @@ if(CMAKE_BUILD_TYPE_UPPER STREQUAL "DEBUG") endif() if(CUDA_COMPUTETARGET AND CUDA_COMPUTETARGET STREQUAL "default") - set(CUDA_COMPUTETARGET 86 89) + set(CUDA_COMPUTETARGET 80-real 86-real 89-real 120-real 75-virtual) endif() if(HIP_AMDGPUTARGET AND HIP_AMDGPUTARGET STREQUAL "default") From cf919bf9a720c0b4135de03feaec600c84111c95 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 29 Dec 2025 22:27:33 +0100 Subject: [PATCH 031/234] GPU Workflow: Fix setting of dEdx processing step --- GPU/GPUTracking/Global/GPUChainTracking.cxx | 2 +- GPU/Workflow/src/GPUWorkflowSpec.cxx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index f370b756e2cdb..5c951053e155b 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -1017,6 +1017,6 @@ void GPUChainTracking::ApplySyncSettings(GPUSettingsProcessing& proc, GPUSetting proc.rtc.optSpecialCode = syncMode; } if (dEdxMode != -2) { - steps.setBits(gpudatatypes::RecoStep::TPCdEdx, dEdxMode == -1 ? !syncMode : dEdxMode > 0); + steps.setBits(gpudatatypes::RecoStep::TPCdEdx, dEdxMode == -1 ? !syncMode : (dEdxMode > 0)); } } diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 6011cc3dc3e9f..2d5a955a5e911 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -187,7 +187,6 @@ void GPURecoWorkflowSpec::init(InitContext& ic) } mConfig->configInterface.outputToExternalBuffers = true; const bool runTracking = mSpecConfig.outputTracks || mSpecConfig.outputCompClustersRoot || mSpecConfig.outputCompClustersFlat; - GPUO2Interface::ApplySyncSettings(mConfig->configProcessing, mConfig->configReconstruction, mConfig->configWorkflow.steps, mConfParam->synchronousProcessing, runTracking ? mConfParam->rundEdx : -2); // Configure the "GPU workflow" i.e. which steps we run on the GPU (or CPU) if (runTracking) { @@ -196,6 +195,8 @@ void GPURecoWorkflowSpec::init(InitContext& ic) gpudatatypes::RecoStep::TPCMerging); mConfig->configWorkflow.outputs.set(gpudatatypes::InOutType::TPCMergedTracks); } + GPUO2Interface::ApplySyncSettings(mConfig->configProcessing, mConfig->configReconstruction, mConfig->configWorkflow.steps, mConfParam->synchronousProcessing, runTracking ? mConfParam->rundEdx : -2); + if (mSpecConfig.outputCompClustersRoot || mSpecConfig.outputCompClustersFlat) { mConfig->configWorkflow.steps.setBits(gpudatatypes::RecoStep::TPCCompression, true); mConfig->configWorkflow.outputs.setBits(gpudatatypes::InOutType::TPCCompressedClusters, true); From 02fde5c462bc123a8d882f9ec1e0796c2a40e540 Mon Sep 17 00:00:00 2001 From: Diego Stocco Date: Mon, 24 Nov 2025 11:34:09 +0100 Subject: [PATCH 032/234] Increase time range search to include QCDB objects created after EOR --- Detectors/MUON/MID/Calibration/macros/build_rejectlist.C | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Detectors/MUON/MID/Calibration/macros/build_rejectlist.C b/Detectors/MUON/MID/Calibration/macros/build_rejectlist.C index 5cec2c611bcf8..06aca991be338 100644 --- a/Detectors/MUON/MID/Calibration/macros/build_rejectlist.C +++ b/Detectors/MUON/MID/Calibration/macros/build_rejectlist.C @@ -28,7 +28,6 @@ #include "TGraph.h" #include "TTimeStamp.h" #include "CCDB/CcdbApi.h" -#include "DataFormatsParameters/GRPECSObject.h" #include "DetectorsCommonDataFormats/DetID.h" #include "DataFormatsMID/ColumnData.h" #include "MIDBase/ColumnDataHandler.h" @@ -111,12 +110,18 @@ std::string timeRangeToString(long start, long end) std::vector findObjectsMDInPeriod(long start, long end, const o2::ccdb::CcdbApi& api, const char* path) { std::vector mds; - auto out = api.list(path, false, "application/json", getTSMS(end), getTSMS(start)); + long creationDelayMS = 300000; // The objects can be created up to 5 minutes after the end of run + auto out = api.list(path, false, "application/json", getTSMS(end) + creationDelayMS, getTSMS(start)); rapidjson::Document doc; doc.Parse(out.c_str()); for (auto& obj : doc["objects"].GetArray()) { MDStruct md; md.start = obj["validFrom"].GetInt64(); + if (getTSMS(end) < getTSMS(md.start)) { + // Since we query on the creation time, adding a delay + // we need to cross-check here that we are within the run + continue; + } md.end = obj["validUntil"].GetInt64(); md.runNumber = std::atoi(obj["RunNumber"].GetString()); md.runType = obj["RunType"].GetString(); From b8c867dbb27d08e9ecf3134aeb72886fbb3c878c Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Thu, 25 Sep 2025 15:57:50 +0200 Subject: [PATCH 033/234] First implementation of loopers inclusion in base Generator class --- .../SimConfig/include/SimConfig/SimConfig.h | 3 + Common/SimConfig/src/SimConfig.cxx | 2 + Generators/CMakeLists.txt | 13 + Generators/include/Generators/Generator.h | 13 + .../include/Generators/TPCLoopersParam.h | 48 ++ Generators/include/TPCLoopers.h | 127 +++++ .../share/egconfig/ScalerComptonParams.json | 28 ++ .../share/egconfig/ScalerPairParams.json | 34 ++ Generators/share/egconfig/gaussian_params.csv | 4 + Generators/share/egconfig/poisson_params.csv | 3 + Generators/src/Generator.cxx | 442 ++++++++++++------ Generators/src/GeneratorsLinkDef.h | 4 + Generators/src/TPCLoopers.cxx | 417 +++++++++++++++++ Generators/src/TPCLoopersParam.cxx | 15 + 14 files changed, 1007 insertions(+), 146 deletions(-) create mode 100644 Generators/include/Generators/TPCLoopersParam.h create mode 100644 Generators/include/TPCLoopers.h create mode 100644 Generators/share/egconfig/ScalerComptonParams.json create mode 100644 Generators/share/egconfig/ScalerPairParams.json create mode 100644 Generators/share/egconfig/gaussian_params.csv create mode 100644 Generators/share/egconfig/poisson_params.csv create mode 100644 Generators/src/TPCLoopers.cxx create mode 100644 Generators/src/TPCLoopersParam.cxx diff --git a/Common/SimConfig/include/SimConfig/SimConfig.h b/Common/SimConfig/include/SimConfig/SimConfig.h index be88d9fbd8c33..8642a0e5bc225 100644 --- a/Common/SimConfig/include/SimConfig/SimConfig.h +++ b/Common/SimConfig/include/SimConfig/SimConfig.h @@ -52,6 +52,7 @@ struct SimConfigData { std::vector mActiveModules; // list of active modules std::vector mReadoutDetectors; // list of readout detectors std::string mMCEngine; // chosen VMC engine + bool mNoLoopers = false; // Disable automatic TPC loopers std::string mGenerator; // chosen VMC generator std::string mTrigger; // chosen VMC generator trigger unsigned int mNEvents; // number of events to be simulated @@ -138,6 +139,8 @@ class SimConfig // get selected active detectors std::vector const& getActiveModules() const { return mConfigData.mActiveModules; } std::vector const& getReadoutDetectors() const { return mConfigData.mReadoutDetectors; } + // get loopers veto + bool getLoopersVeto() const { return mConfigData.mNoLoopers; } // static helper functions to determine list of active / readout modules // can also be used from outside diff --git a/Common/SimConfig/src/SimConfig.cxx b/Common/SimConfig/src/SimConfig.cxx index 15879687872d5..5ddc3199e3d4a 100644 --- a/Common/SimConfig/src/SimConfig.cxx +++ b/Common/SimConfig/src/SimConfig.cxx @@ -74,6 +74,7 @@ void SimConfig::initOptions(boost::program_options::options_description& options "run", bpo::value()->default_value(-1), "ALICE run number")( "asservice", bpo::value()->default_value(false), "run in service/server mode")( "noGeant", bpo::bool_switch(), "prohibits any Geant transport/physics (by using tight cuts)")( + "noLoopers", bpo::bool_switch(), "disable automatic TPC loopers")( "forwardKine", bpo::bool_switch(), "forward kinematics on a FairMQ channel")( "noDiscOutput", bpo::bool_switch(), "switch off writing sim results to disc (useful in combination with forwardKine)"); options.add_options()("fromCollContext", bpo::value()->default_value(""), "Use a pregenerated collision context to infer number of events to simulate, how to embedd them, the vertex position etc. Takes precedence of other options such as \"--nEvents\". The format is COLLISIONCONTEXTFILE.root[:SIGNALNAME] where SIGNALNAME is the event part in the context which is relevant."); @@ -297,6 +298,7 @@ bool SimConfig::resetFromParsedMap(boost::program_options::variables_map const& using o2::detectors::DetID; mConfigData.mMCEngine = vm["mcEngine"].as(); mConfigData.mNoGeant = vm["noGeant"].as(); + mConfigData.mNoLoopers = vm["noLoopers"].as(); // Reset modules and detectors as they are anyway re-parsed mConfigData.mReadoutDetectors.clear(); diff --git a/Generators/CMakeLists.txt b/Generators/CMakeLists.txt index 02caa63df0d43..56fe8b8fc2284 100644 --- a/Generators/CMakeLists.txt +++ b/Generators/CMakeLists.txt @@ -41,6 +41,8 @@ o2_add_library(Generators src/GeneratorTParticleParam.cxx src/GeneratorService.cxx src/FlowMapper.cxx + $<$:src/TPCLoopers.cxx> + $<$:src/TPCLoopersParam.cxx> $<$:src/GeneratorPythia8.cxx> $<$:src/DecayerPythia8.cxx> $<$:src/GeneratorPythia8Param.cxx> @@ -53,6 +55,7 @@ o2_add_library(Generators PUBLIC_LINK_LIBRARIES FairRoot::Base O2::SimConfig O2::CommonUtils O2::DetectorsBase O2::ZDCBase O2::SimulationDataFormat ${pythiaTarget} ${hepmcTarget} FairRoot::Gen + $<$:onnxruntime::onnxruntime> TARGETVARNAME targetName) if(pythia_FOUND) @@ -63,6 +66,10 @@ if(HepMC3_FOUND) target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_HEPMC3) endif() +if(onnxruntime_FOUND) + target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_ONNXRUNTIME) +endif() + set(headers include/Generators/Generator.h include/Generators/Trigger.h @@ -88,6 +95,12 @@ set(headers include/Generators/FlowMapper.h ) +if(onnxruntime_FOUND) + list(APPEND headers + include/Generators/TPCLoopers.h + include/Generators/TPCLoopersParam.h) +endif() + if(pythia_FOUND) list(APPEND headers include/Generators/GeneratorPythia8.h diff --git a/Generators/include/Generators/Generator.h b/Generators/include/Generators/Generator.h index bd35a00793e2d..374d53f324399 100644 --- a/Generators/include/Generators/Generator.h +++ b/Generators/include/Generators/Generator.h @@ -17,6 +17,10 @@ #include "FairGenerator.h" #include "TParticle.h" #include "Generators/Trigger.h" +#ifdef GENERATORS_WITH_ONNXRUNTIME +#include "Generators/TPCLoopers.h" +#include "Generators/TPCLoopersParam.h" +#endif #include #include #include @@ -73,6 +77,7 @@ class Generator : public FairGenerator /** methods to override **/ virtual Bool_t generateEvent() = 0; // generates event (in structure internal to generator) virtual Bool_t importParticles() = 0; // fills the mParticles vector (transfer from generator state) + Bool_t loopers(); // adds loopers to the event in case TPC is used virtual void updateHeader(o2::dataformats::MCEventHeader* eventHeader) {}; Bool_t triggerEvent(); @@ -154,6 +159,8 @@ class Generator : public FairGenerator private: void updateSubGeneratorInformation(o2::dataformats::MCEventHeader* header) const; + // loopers flag + Bool_t mAddLoopers = kFALSE; // collect an ID and a short description of sub-generator entities std::unordered_map mSubGeneratorsIdToDesc; // the current ID of the sub-generator used in the current event (if applicable) @@ -162,6 +169,12 @@ class Generator : public FairGenerator // global static information about (upper limit of) number of events to be generated static unsigned int gTotalNEvents; +#ifdef GENERATORS_WITH_ONNXRUNTIME + // Loopers generator instance + std::unique_ptr mLoopersGen = nullptr; +#endif + void initLoopersGen(); + ClassDefOverride(Generator, 2); }; /** class Generator **/ diff --git a/Generators/include/Generators/TPCLoopersParam.h b/Generators/include/Generators/TPCLoopersParam.h new file mode 100644 index 0000000000000..ceeea201538b2 --- /dev/null +++ b/Generators/include/Generators/TPCLoopersParam.h @@ -0,0 +1,48 @@ +// Copyright 2024-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author M+Giacalone - September 2025 + +#ifndef ALICEO2_EVENTGEN_TPCLOOPERSPARAM_H_ +#define ALICEO2_EVENTGEN_TPCLOOPERSPARAM_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +namespace o2 +{ +namespace eventgen +{ + +/** + ** a parameter class/struct to keep the settings of + ** the tpc loopers event-generator and + ** allow the user to modify them + **/ +struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper { + std::string model_pairs = "ccdb://Users/m/mgiacalo/WGAN_ExtGenPair"; // ONNX model for e+e- pair production + std::string model_compton = "ccdb://Users/m/mgiacalo/WGAN_ExtGenCompton"; // ONNX model for Compton scattering + std::string poisson = "${O2_ROOT}/share/Generators/egconfig/poisson_params.csv"; // file with Poissonian parameters + std::string gauss = "${O2_ROOT}/share/Generators/egconfig/gaussian_params.csv"; // file with Gaussian parameters + std::string scaler_pair = "${O2_ROOT}/share/Generators/egconfig/ScalerPairParams.json"; // file with scaler parameters for e+e- pair production + std::string scaler_compton = "${O2_ROOT}/share/Generators/egconfig/ScalerComptonParams.json"; // file with scaler parameters for Compton scattering + bool flat_gas = true; // if true, the gas density is considered flat in the TPC volume + int nFlatGasLoopers = 500; // number of loopers to be generated per event in case of flat gas + float fraction_pairs = 0.08; // fraction of loopers + std::array multiplier = {1., 1.}; // multiplier for pairs and compton loopers for Poissonian and Gaussian sampling + std::array fixedNLoopers = {1, 1}; // fixed number of loopers coming from pairs and compton electrons - valid if flat gas is false and both Poisson and Gaussian params files are empty + O2ParamDef(GenTPCLoopersParam, "GenTPCLoopers"); +}; + +} // end namespace eventgen +} // end namespace o2 + +#endif // ALICEO2_EVENTGEN_TPCLOOPERSPARAM_H_ diff --git a/Generators/include/TPCLoopers.h b/Generators/include/TPCLoopers.h new file mode 100644 index 0000000000000..70146a82baf60 --- /dev/null +++ b/Generators/include/TPCLoopers.h @@ -0,0 +1,127 @@ +#ifndef ALICEO2_EVENTGEN_TPCLOOPERS_H_ +#define ALICEO2_EVENTGEN_TPCLOOPERS_H_ + +#ifdef GENERATORS_WITH_ONNXRUNTIME +#include +#endif +#include +#include +#include +#include +#include "CCDB/CCDBTimeStampUtils.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsRaw/HBFUtils.h" +#include "TRandom3.h" +#include "TDatabasePDG.h" +#include +#include +#include "SimulationDataFormat/MCGenProperties.h" +#include "TParticle.h" +#include + +#ifdef GENERATORS_WITH_ONNXRUNTIME +// Static Ort::Env instance for multiple onnx model loading +extern Ort::Env global_env; +#endif + +#ifdef GENERATORS_WITH_ONNXRUNTIME +// This class is responsible for loading the scaler parameters from a JSON file +// and applying the inverse transformation to the generated data. +struct Scaler +{ + std::vector normal_min; + std::vector normal_max; + std::vector outlier_center; + std::vector outlier_scale; + + void load(const std::string &filename); + + std::vector inverse_transform(const std::vector &input); + +private: + std::vector jsonArrayToVector(const rapidjson::Value &jsonArray); +}; + +// This class loads the ONNX model and generates samples using it. +class ONNXGenerator +{ +public: + ONNXGenerator(Ort::Env &shared_env, const std::string &model_path); + + std::vector generate_sample(); + +private: + Ort::Env &env; + Ort::Session session; + TRandom3 rand_gen; +}; +#endif // GENERATORS_WITH_ONNXRUNTIME + +namespace o2 +{ +namespace eventgen +{ + +#ifdef GENERATORS_WITH_ONNXRUNTIME +class GenTPCLoopers +{ + public: + GenTPCLoopers(std::string model_pairs = "tpcloopmodel.onnx", std::string model_compton = "tpcloopmodelcompton.onnx", + std::string poisson = "poisson.csv", std::string gauss = "gauss.csv", std::string scaler_pair = "scaler_pair.json", + std::string scaler_compton = "scaler_compton.json"); + + Bool_t generateEvent(); + + Bool_t generateEvent(double &time_limit); + + std::vector importParticles(); + + unsigned int PoissonPairs(); + + unsigned int GaussianElectrons(); + + void SetNLoopers(unsigned int &nsig_pair, unsigned int &nsig_compton); + + void SetMultiplier(std::array &mult); + + void setFlatGas(Bool_t &flat, const Int_t &number = -1); + + void setFractionPairs(float &fractionPairs); + + private: + std::unique_ptr mONNX_pair = nullptr; + std::unique_ptr mONNX_compton = nullptr; + std::unique_ptr mScaler_pair = nullptr; + std::unique_ptr mScaler_compton = nullptr; + double mPoisson[3] = {0.0, 0.0, 0.0}; // Mu, Min and Max of Poissonian + double mGauss[4] = {0.0, 0.0, 0.0, 0.0}; // Mean, Std, Min, Max + std::vector> mGenPairs; + std::vector> mGenElectrons; + unsigned int mNLoopersPairs = -1; + unsigned int mNLoopersCompton = -1; + std::array mMultiplier = {1., 1.}; + bool mPoissonSet = false; + bool mGaussSet = false; + // Random number generator + TRandom3 mRandGen; + // Masses of the electrons and positrons + TDatabasePDG *mPDG = TDatabasePDG::Instance(); + double mMass_e = mPDG->GetParticle(11)->Mass(); + double mMass_p = mPDG->GetParticle(-11)->Mass(); + int mCurrentEvent = 0; // Current event number, used for adaptive loopers + TFile *mContextFile = nullptr; // Input collision context file + o2::steer::DigitizationContext *mCollisionContext = nullptr; // Pointer to the digitization context + std::vector mInteractionTimeRecords; // Interaction time records from collision context + Bool_t mFlatGas = false; // Flag to indicate if flat gas loopers are used + Int_t mFlatGasNumber = -1; // Number of flat gas loopers per event + double mIntTimeRecMean = 1.0; // Average interaction time record used for the reference + double mTimeLimit = 0.0; // Time limit for the current event + double mTimeEnd = 0.0; // Time limit for the last event + float mLoopsFractionPairs = 0.08; // Fraction of loopers from Pairs +}; +#endif // GENERATORS_WITH_ONNXRUNTIME + +} // namespace eventgen +} // namespace o2 + +#endif // ALICEO2_EVENTGEN_TPCLOOPERS_H_ \ No newline at end of file diff --git a/Generators/share/egconfig/ScalerComptonParams.json b/Generators/share/egconfig/ScalerComptonParams.json new file mode 100644 index 0000000000000..d8e654847f46e --- /dev/null +++ b/Generators/share/egconfig/ScalerComptonParams.json @@ -0,0 +1,28 @@ +{ + "normal": { + "min": [ + -0.0108811147511005, + -0.0098758740350604, + -0.0103233363479375, + -260.0542297363281, + -259.80059814453125 + ], + "max": [ + 0.0108060473576188, + 0.0103057539090514, + 0.0106524610891938, + 260.0343933105469, + 259.62890625 + ] + }, + "outlier": { + "center": [ + -71.39387130737305, + 96791.23828125 + ], + "scale": [ + 265.9389114379883, + 230762.30981445312 + ] + } +} \ No newline at end of file diff --git a/Generators/share/egconfig/ScalerPairParams.json b/Generators/share/egconfig/ScalerPairParams.json new file mode 100644 index 0000000000000..61434bfa2462e --- /dev/null +++ b/Generators/share/egconfig/ScalerPairParams.json @@ -0,0 +1,34 @@ +{ + "normal": { + "min": [ + -0.0073022879660129, + -0.0077305701561272, + -0.0076750442385673, + -0.0082916170358657, + -0.0079681202769279, + -0.0077468422241508, + -255.6164093017578, + -252.9441680908203 + ], + "max": [ + 0.007688719779253, + 0.0077241472899913, + 0.0075828479602932, + 0.00813714787364, + 0.0083825681358575, + 0.0073839174583554, + 256.2904968261719, + 253.4925842285156 + ] + }, + "outlier": { + "center": [ + -79.66580963134766, + 141535.640625 + ], + "scale": [ + 250.8921127319336, + 222363.16015625 + ] + } +} \ No newline at end of file diff --git a/Generators/share/egconfig/gaussian_params.csv b/Generators/share/egconfig/gaussian_params.csv new file mode 100644 index 0000000000000..8e07c22dd30bf --- /dev/null +++ b/Generators/share/egconfig/gaussian_params.csv @@ -0,0 +1,4 @@ +9.611554230339172022e+01 +1.963570744941765867e+01 +4.300000000000000000e+01 +1.690000000000000000e+02 diff --git a/Generators/share/egconfig/poisson_params.csv b/Generators/share/egconfig/poisson_params.csv new file mode 100644 index 0000000000000..ef26bd973d34c --- /dev/null +++ b/Generators/share/egconfig/poisson_params.csv @@ -0,0 +1,3 @@ +3.165383056343737511e+00 +1.000000000000000000e+00 +1.200000000000000000e+01 diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 9204ede98215e..153ef5cd5e35e 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -17,11 +17,14 @@ #include "SimulationDataFormat/MCEventHeader.h" #include "SimulationDataFormat/ParticleStatus.h" #include "SimulationDataFormat/MCGenProperties.h" +#include #include "FairPrimaryGenerator.h" #include #include #include "TClonesArray.h" #include "TParticle.h" +#include "TSystem.h" +#include "TGrid.h" namespace o2 { @@ -39,6 +42,18 @@ Generator::Generator() : FairGenerator("ALICEo2", "ALICEo2 Generator"), /** default constructor **/ mThisInstanceID = Generator::InstanceCounter; Generator::InstanceCounter++; + auto simConfig = o2::conf::SimConfig::Instance(); + auto noLoops = simConfig.getLoopersVeto(); + if (!noLoops) { + bool transport = (simConfig.getMCEngine() != "O2TrivialMCEngine"); + if (transport) { + bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); + if (tpcActive) { + mAddLoopers = kTRUE; + initLoopersGen(); + } + } + } } /*****************************************************************/ @@ -49,6 +64,102 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na /** constructor **/ mThisInstanceID = Generator::InstanceCounter; Generator::InstanceCounter++; + auto simConfig = o2::conf::SimConfig::Instance(); + auto noLoops = simConfig.getLoopersVeto(); + if (!noLoops) { + bool transport = (simConfig.getMCEngine() != "O2TrivialMCEngine"); + if (transport) { + bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); + if (tpcActive) { + mAddLoopers = kTRUE; + initLoopersGen(); + } + } + } +} + +/*****************************************************************/ + +void Generator::initLoopersGen() +{ +#ifdef GENERATORS_WITH_ONNXRUNTIME + // Expand all environment paths + const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); + std::string model_pairs = gSystem->ExpandPathName(loopersParam.model_pairs.c_str()); + std::string model_compton = gSystem->ExpandPathName(loopersParam.model_compton.c_str()); + const auto& scaler_pair = gSystem->ExpandPathName(loopersParam.scaler_pair.c_str()); + const auto& scaler_compton = gSystem->ExpandPathName(loopersParam.scaler_compton.c_str()); + const auto& poisson = gSystem->ExpandPathName(loopersParam.poisson.c_str()); + const auto& gauss = gSystem->ExpandPathName(loopersParam.gauss.c_str()); + auto flat_gas = loopersParam.flat_gas; + const auto& nFlatGasLoopers = loopersParam.nFlatGasLoopers; + auto fraction_pairs = loopersParam.fraction_pairs; + auto multiplier = loopersParam.multiplier; + auto fixedNLoopers = loopersParam.fixedNLoopers; + const std::array models = {model_pairs, model_compton}; + const std::array local_names = {"WGANpair.onnx", "WGANcompton.onnx"}; + const std::array isAlien = {models[0].starts_with("alien://"), models[1].starts_with("alien://")}; + const std::array isCCDB = {models[0].starts_with("ccdb://"), models[1].starts_with("ccdb://")}; + if (std::any_of(isAlien.begin(), isAlien.end(), [](bool v) { return v; })) { + if (!gGrid) { + TGrid::Connect("alien://"); + if (!gGrid) { + LOG(fatal) << "AliEn connection failed, check token."; + exit(1); + } + } + for (size_t i = 0; i < models.size(); ++i) { + if (isAlien[i] && !TFile::Cp(models[i].c_str(), local_names[i].c_str())) { + LOG(fatal) << "Error: Model file " << models[i] << " does not exist!"; + exit(1); + } + } + } + if (std::any_of(isCCDB.begin(), isCCDB.end(), [](bool v) { return v; })) { + o2::ccdb::CcdbApi ccdb_api; + ccdb_api.init("http://alice-ccdb.cern.ch"); + for (size_t i = 0; i < models.size(); ++i) { + if (isCCDB[i]) { + auto model_path = models[i].substr(7); // Remove "ccdb://" + // Treat filename if provided in the CCDB path + auto extension = model_path.find(".onnx"); + if (extension != std::string::npos) { + auto last_slash = model_path.find_last_of('/'); + model_path = model_path.substr(0, last_slash); + } + std::map filter; + if (!ccdb_api.retrieveBlob(model_path, "./", filter, o2::ccdb::getCurrentTimestamp(), false, local_names[i].c_str())) { + LOG(fatal) << "Error: issues in retrieving " << model_path << " from CCDB!"; + exit(1); + } + } + } + } + model_pairs = isAlien[0] || isCCDB[0] ? local_names[0] : model_pairs; + model_compton = isAlien[1] || isCCDB[1] ? local_names[1] : model_compton; + try { + // Create the TPC loopers generator with the provided parameters + mLoopersGen = std::make_unique(model_pairs, model_compton, poisson, gauss, scaler_pair, scaler_compton); + + // Configure the generator with flat gas loopers if enabled (default) + if (flat_gas) { + mLoopersGen->setFlatGas(flat_gas, nFlatGasLoopers); + mLoopersGen->setFractionPairs(fraction_pairs); + } else { + // Otherwise, Poisson+Gauss sampling or fixed number of loopers will be used + // Multiplier is applied only with distribution sampling + // This configuration can be used for testing purposes, in all other cases flat gas is recommended + mLoopersGen->SetNLoopers(fixedNLoopers[0], fixedNLoopers[1]); + mLoopersGen->SetMultiplier(multiplier); + } + LOG(info) << "TPC Loopers generator initialized successfully"; + } catch (const std::exception& e) { + LOG(error) << "Failed to initialize TPC Loopers generator: " << e.what(); + mLoopersGen.reset(); + } +#else + LOG(warn) << "ONNX Runtime support not available, cannot initialize TPC loopers generator"; +#endif } /*****************************************************************/ @@ -65,191 +176,230 @@ Bool_t /*****************************************************************/ Bool_t - Generator::ReadEvent(FairPrimaryGenerator* primGen) + Generator::loopers() { - /** read event **/ - - /** endless generate-and-trigger loop **/ - while (true) { - mReadEventCounter++; - - /** clear particle vector **/ - mParticles.clear(); - - /** reset the sub-generator ID **/ - mSubGeneratorId = -1; - - /** generate event **/ - if (!generateEvent()) { - LOG(error) << "ReadEvent failed in generateEvent"; - return kFALSE; - } - - /** import particles **/ - if (!importParticles()) { - LOG(error) << "ReadEvent failed in importParticles"; - return kFALSE; - } - - if (mSubGeneratorsIdToDesc.empty() && mSubGeneratorId > -1) { - LOG(fatal) << "ReadEvent failed because no SubGenerator description given"; - } - - if (!mSubGeneratorsIdToDesc.empty() && mSubGeneratorId < 0) { - LOG(fatal) << "ReadEvent failed because SubGenerator description given but sub-generator not set"; - } - - /** trigger event **/ - if (triggerEvent()) { - mTriggerOkHook(mParticles, mReadEventCounter); - break; - } else { - mTriggerFalseHook(mParticles, mReadEventCounter); - } +#ifdef GENERATORS_WITH_ONNXRUNTIME + if (!mLoopersGen) { + LOG(error) << "Loopers generator not initialized"; + return kFALSE; } - /** add tracks **/ - if (!addTracks(primGen)) { - LOG(error) << "ReadEvent failed in addTracks"; + // Generate loopers using the initialized TPC loopers generator + if (!mLoopersGen->generateEvent()) { + LOG(error) << "Failed to generate loopers event"; return kFALSE; } - - /** update header **/ - auto header = primGen->GetEvent(); - auto o2header = dynamic_cast(header); - if (!header) { - LOG(fatal) << "MC event header is not a 'o2::dataformats::MCEventHeader' object"; + const auto& looperParticles = mLoopersGen->importParticles(); + if (looperParticles.empty()) { + LOG(error) << "Failed to import loopers particles"; return kFALSE; } - updateHeader(o2header); - updateSubGeneratorInformation(o2header); + // Append the generated looper particles to the main particle list + mParticles.insert(mParticles.end(), looperParticles.begin(), looperParticles.end()); - /** success **/ + LOG(debug) << "Added " << looperParticles.size() << " looper particles"; + return kTRUE; +#else + LOG(warn) << "ONNX Runtime support not available, skipping TPC loopers generation"; return kTRUE; +#endif } + /*****************************************************************/ + + Bool_t + Generator::ReadEvent(FairPrimaryGenerator * primGen) + { + /** read event **/ + + /** endless generate-and-trigger loop **/ + while (true) { + mReadEventCounter++; + + /** clear particle vector **/ + mParticles.clear(); + + /** reset the sub-generator ID **/ + mSubGeneratorId = -1; + + /** generate event **/ + if (!generateEvent()) { + LOG(error) << "ReadEvent failed in generateEvent"; + return kFALSE; + } + + /** import particles **/ + if (!importParticles()) { + LOG(error) << "ReadEvent failed in importParticles"; + return kFALSE; + } + + /** Add loopers **/ + if(mAddLoopers){ + if (!loopers()) { + LOG(error) << "ReadEvent failed in loopers"; + return kFALSE; + } + } + + if (mSubGeneratorsIdToDesc.empty() && mSubGeneratorId > -1) { + LOG(fatal) << "ReadEvent failed because no SubGenerator description given"; + } + + if (!mSubGeneratorsIdToDesc.empty() && mSubGeneratorId < 0) { + LOG(fatal) << "ReadEvent failed because SubGenerator description given but sub-generator not set"; + } + + /** trigger event **/ + if (triggerEvent()) { + mTriggerOkHook(mParticles, mReadEventCounter); + break; + } else { + mTriggerFalseHook(mParticles, mReadEventCounter); + } + } -/*****************************************************************/ + /** add tracks **/ + if (!addTracks(primGen)) { + LOG(error) << "ReadEvent failed in addTracks"; + return kFALSE; + } -Bool_t - Generator::addTracks(FairPrimaryGenerator* primGen) -{ - /** add tracks **/ + /** update header **/ + auto header = primGen->GetEvent(); + auto o2header = dynamic_cast(header); + if (!header) { + LOG(fatal) << "MC event header is not a 'o2::dataformats::MCEventHeader' object"; + return kFALSE; + } + updateHeader(o2header); + updateSubGeneratorInformation(o2header); - auto o2primGen = dynamic_cast(primGen); - if (!o2primGen) { - LOG(fatal) << "PrimaryGenerator is not a o2::eventgen::PrimaryGenerator"; - return kFALSE; + /** success **/ + return kTRUE; } - /** loop over particles **/ - for (const auto& particle : mParticles) { - o2primGen->AddTrack(particle.GetPdgCode(), - particle.Px() * mMomentumUnit, - particle.Py() * mMomentumUnit, - particle.Pz() * mMomentumUnit, - particle.Vx() * mPositionUnit, - particle.Vy() * mPositionUnit, - particle.Vz() * mPositionUnit, - particle.GetMother(0), - particle.GetMother(1), - particle.GetDaughter(0), - particle.GetDaughter(1), - particle.TestBit(ParticleStatus::kToBeDone), - particle.Energy() * mEnergyUnit, - particle.T() * mTimeUnit, - particle.GetWeight(), - (TMCProcess)particle.GetUniqueID(), - particle.GetStatusCode()); // generator status information passed as status code field - } + /*****************************************************************/ - /** success **/ - return kTRUE; -} + Bool_t + Generator::addTracks(FairPrimaryGenerator * primGen) + { + /** add tracks **/ -/*****************************************************************/ + auto o2primGen = dynamic_cast(primGen); + if (!o2primGen) { + LOG(fatal) << "PrimaryGenerator is not a o2::eventgen::PrimaryGenerator"; + return kFALSE; + } -Bool_t - Generator::boostEvent() -{ - /** boost event **/ + /** loop over particles **/ + for (const auto& particle : mParticles) { + o2primGen->AddTrack(particle.GetPdgCode(), + particle.Px() * mMomentumUnit, + particle.Py() * mMomentumUnit, + particle.Pz() * mMomentumUnit, + particle.Vx() * mPositionUnit, + particle.Vy() * mPositionUnit, + particle.Vz() * mPositionUnit, + particle.GetMother(0), + particle.GetMother(1), + particle.GetDaughter(0), + particle.GetDaughter(1), + particle.TestBit(ParticleStatus::kToBeDone), + particle.Energy() * mEnergyUnit, + particle.T() * mTimeUnit, + particle.GetWeight(), + (TMCProcess)particle.GetUniqueID(), + particle.GetStatusCode()); // generator status information passed as status code field + } - /** success **/ - return kTRUE; -} + /** success **/ + return kTRUE; + } -/*****************************************************************/ + /*****************************************************************/ -Bool_t - Generator::triggerEvent() -{ - /** trigger event **/ + Bool_t + Generator::boostEvent() + { + /** boost event **/ - /** check trigger presence **/ - if (mTriggers.size() == 0 && mDeepTriggers.size() == 0) { + /** success **/ return kTRUE; } - /** check trigger mode **/ - Bool_t triggered; - if (mTriggerMode == kTriggerOFF) { - return kTRUE; - } else if (mTriggerMode == kTriggerOR) { - triggered = kFALSE; - } else if (mTriggerMode == kTriggerAND) { - triggered = kTRUE; - } else { - return kTRUE; - } + /*****************************************************************/ - /** loop over triggers **/ - for (const auto& trigger : mTriggers) { - auto retval = trigger(mParticles); - if (mTriggerMode == kTriggerOR) { - triggered |= retval; + Bool_t + Generator::triggerEvent() + { + /** trigger event **/ + + /** check trigger presence **/ + if (mTriggers.size() == 0 && mDeepTriggers.size() == 0) { + return kTRUE; } - if (mTriggerMode == kTriggerAND) { - triggered &= retval; + + /** check trigger mode **/ + Bool_t triggered; + if (mTriggerMode == kTriggerOFF) { + return kTRUE; + } else if (mTriggerMode == kTriggerOR) { + triggered = kFALSE; + } else if (mTriggerMode == kTriggerAND) { + triggered = kTRUE; + } else { + return kTRUE; } - } - /** loop over deep triggers **/ - for (const auto& trigger : mDeepTriggers) { - auto retval = trigger(mInterface, mInterfaceName); - if (mTriggerMode == kTriggerOR) { - triggered |= retval; + /** loop over triggers **/ + for (const auto& trigger : mTriggers) { + auto retval = trigger(mParticles); + if (mTriggerMode == kTriggerOR) { + triggered |= retval; + } + if (mTriggerMode == kTriggerAND) { + triggered &= retval; + } } - if (mTriggerMode == kTriggerAND) { - triggered &= retval; + + /** loop over deep triggers **/ + for (const auto& trigger : mDeepTriggers) { + auto retval = trigger(mInterface, mInterfaceName); + if (mTriggerMode == kTriggerOR) { + triggered |= retval; + } + if (mTriggerMode == kTriggerAND) { + triggered &= retval; + } } - } - /** return **/ - return triggered; -} + /** return **/ + return triggered; + } -/*****************************************************************/ + /*****************************************************************/ -void Generator::addSubGenerator(int subGeneratorId, std::string const& subGeneratorDescription) -{ - if (subGeneratorId < 0) { - LOG(fatal) << "Sub-generator IDs must be >= 0, instead, passed value is " << subGeneratorId; + void Generator::addSubGenerator(int subGeneratorId, std::string const& subGeneratorDescription) + { + if (subGeneratorId < 0) { + LOG(fatal) << "Sub-generator IDs must be >= 0, instead, passed value is " << subGeneratorId; + } + mSubGeneratorsIdToDesc.insert({subGeneratorId, subGeneratorDescription}); } - mSubGeneratorsIdToDesc.insert({subGeneratorId, subGeneratorDescription}); -} -/*****************************************************************/ + /*****************************************************************/ -void Generator::updateSubGeneratorInformation(o2::dataformats::MCEventHeader* header) const -{ - if (mSubGeneratorId < 0) { - return; + void Generator::updateSubGeneratorInformation(o2::dataformats::MCEventHeader * header) const + { + if (mSubGeneratorId < 0) { + return; + } + header->putInfo(o2::mcgenid::GeneratorProperty::SUBGENERATORID, mSubGeneratorId); + header->putInfo>(o2::mcgenid::GeneratorProperty::SUBGENERATORDESCRIPTIONMAP, mSubGeneratorsIdToDesc); } - header->putInfo(o2::mcgenid::GeneratorProperty::SUBGENERATORID, mSubGeneratorId); - header->putInfo>(o2::mcgenid::GeneratorProperty::SUBGENERATORDESCRIPTIONMAP, mSubGeneratorsIdToDesc); -} -/*****************************************************************/ -/*****************************************************************/ + /*****************************************************************/ + /*****************************************************************/ } /* namespace eventgen */ } /* namespace o2 */ diff --git a/Generators/src/GeneratorsLinkDef.h b/Generators/src/GeneratorsLinkDef.h index 2b8d42f86bf9b..97896d8225042 100644 --- a/Generators/src/GeneratorsLinkDef.h +++ b/Generators/src/GeneratorsLinkDef.h @@ -35,6 +35,10 @@ #pragma link C++ class o2::eventgen::GeneratorFromEventPool + ; #pragma link C++ class o2::eventgen::GeneratorEventPoolParam + ; #pragma link C++ class o2::eventgen::EventPoolGenConfig + ; +#ifdef GENERATORS_WITH_ONNXRUNTIME +#pragma link C++ class o2::eventgen::GenTPCLoopers + ; +#pragma link C++ class o2::eventgen::GenTPCLoopersParam + ; +#endif #pragma link C++ class o2::conf::ConfigurableParamPromoter < o2::eventgen::GeneratorEventPoolParam, o2::eventgen::EventPoolGenConfig> + ; #ifdef GENERATORS_WITH_HEPMC3 #pragma link C++ class o2::eventgen::GeneratorHepMC + ; diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx new file mode 100644 index 0000000000000..4eacb7674599c --- /dev/null +++ b/Generators/src/TPCLoopers.cxx @@ -0,0 +1,417 @@ +#include "Generators/TPCLoopers.h" + +// Static Ort::Env instance for multiple onnx model loading +Ort::Env global_env(ORT_LOGGING_LEVEL_WARNING, "GlobalEnv"); + +// This class is responsible for loading the scaler parameters from a JSON file +// and applying the inverse transformation to the generated data. + +void Scaler::load(const std::string &filename) +{ + std::ifstream file(filename); + if (!file.is_open()) { + throw std::runtime_error("Error: Could not open scaler file!"); + } + + std::string json_str((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + file.close(); + + rapidjson::Document doc; + doc.Parse(json_str.c_str()); + + if (doc.HasParseError()) { + throw std::runtime_error("Error: JSON parsing failed!"); + } + + normal_min = jsonArrayToVector(doc["normal"]["min"]); + normal_max = jsonArrayToVector(doc["normal"]["max"]); + outlier_center = jsonArrayToVector(doc["outlier"]["center"]); + outlier_scale = jsonArrayToVector(doc["outlier"]["scale"]); + std::vector normal_min; + std::vector normal_max; + std::vector outlier_center; + std::vector outlier_scale; +} + +std::vector Scaler::inverse_transform(const std::vector &input) +{ + std::vector output; + for (int i = 0; i < input.size(); ++i) + { + if (i < input.size() - 2) + output.push_back(input[i] * (normal_max[i] - normal_min[i]) + normal_min[i]); + else + output.push_back(input[i] * outlier_scale[i - (input.size() - 2)] + outlier_center[i - (input.size() - 2)]); + } + + return output; +} + +std::vector Scaler::jsonArrayToVector(const rapidjson::Value &jsonArray) +{ + std::vector vec; + for (int i = 0; i < jsonArray.Size(); ++i) + { + vec.push_back(jsonArray[i].GetDouble()); + } + return vec; +} + +// This class loads the ONNX model and generates samples using it. + +ONNXGenerator::ONNXGenerator(Ort::Env& shared_env, const std::string& model_path) +: env(shared_env), session(env, model_path.c_str(), Ort::SessionOptions{}) +{ + // Create session options + Ort::SessionOptions session_options; + session = Ort::Session(env, model_path.c_str(), session_options); +} + +std::vector ONNXGenerator::generate_sample() +{ + Ort::AllocatorWithDefaultOptions allocator; + + // Generate a latent vector (z) + std::vector z(100); + for (auto &v : z) + v = rand_gen.Gaus(0.0, 1.0); + + // Prepare input tensor + std::vector input_shape = {1, 100}; + // Get memory information + Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); + + // Create input tensor correctly + Ort::Value input_tensor = Ort::Value::CreateTensor( + memory_info, z.data(), z.size(), input_shape.data(), input_shape.size()); + // Run inference + const char *input_names[] = {"z"}; + const char *output_names[] = {"output"}; + auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_names, &input_tensor, 1, output_names, 1); + + // Extract output + float *output_data = output_tensors.front().GetTensorMutableData(); + // Get the size of the output tensor + auto output_tensor_info = output_tensors.front().GetTensorTypeAndShapeInfo(); + size_t output_data_size = output_tensor_info.GetElementCount(); // Total number of elements in the tensor + std::vector output; + for (int i = 0; i < output_data_size; ++i) + { + output.push_back(output_data[i]); + } + + return output; +} + +namespace o2 +{ +namespace eventgen +{ + +GenTPCLoopers::GenTPCLoopers(std::string model_pairs, std::string model_compton, + std::string poisson, std::string gauss, std::string scaler_pair, + std::string scaler_compton) +{ + // Checking if the model files exist and are not empty + std::ifstream model_file[2]; + model_file[0].open(model_pairs); + model_file[1].open(model_compton); + if (!model_file[0].is_open() || model_file[0].peek() == std::ifstream::traits_type::eof()) + { + LOG(fatal) << "Error: Pairs model file is empty or does not exist!"; + exit(1); + } + if (!model_file[1].is_open() || model_file[1].peek() == std::ifstream::traits_type::eof()) + { + LOG(fatal) << "Error: Compton model file is empty or does not exist!"; + exit(1); + } + model_file[0].close(); + model_file[1].close(); + // Checking if the scaler files exist and are not empty + std::ifstream scaler_file[2]; + scaler_file[0].open(scaler_pair); + scaler_file[1].open(scaler_compton); + if (!scaler_file[0].is_open() || scaler_file[0].peek() == std::ifstream::traits_type::eof()) + { + LOG(fatal) << "Error: Pairs scaler file is empty or does not exist!"; + exit(1); + } + if (!scaler_file[1].is_open() || scaler_file[1].peek() == std::ifstream::traits_type::eof()) + { + LOG(fatal) << "Error: Compton scaler file is empty or does not exist!"; + exit(1); + } + scaler_file[0].close(); + scaler_file[1].close(); + // Checking if the poisson file exists and it's not empty + if (poisson != "") + { + std::ifstream poisson_file(poisson); + if (!poisson_file.is_open() || poisson_file.peek() == std::ifstream::traits_type::eof()) + { + LOG(fatal) << "Error: Poisson file is empty or does not exist!"; + exit(1); + } + else + { + poisson_file >> mPoisson[0] >> mPoisson[1] >> mPoisson[2]; + poisson_file.close(); + mPoissonSet = true; + } + } + // Checking if the gauss file exists and it's not empty + if (gauss != "") + { + std::ifstream gauss_file(gauss); + if (!gauss_file.is_open() || gauss_file.peek() == std::ifstream::traits_type::eof()) + { + LOG(fatal) << "Error: Gauss file is empty or does not exist!"; + exit(1); + } + else + { + gauss_file >> mGauss[0] >> mGauss[1] >> mGauss[2] >> mGauss[3]; + gauss_file.close(); + mGaussSet = true; + } + } + mONNX_pair = std::make_unique(global_env, model_pairs); + mScaler_pair = std::make_unique(); + mScaler_pair->load(scaler_pair); + mONNX_compton = std::make_unique(global_env, model_compton); + mScaler_compton = std::make_unique(); + mScaler_compton->load(scaler_compton); +} + +Bool_t GenTPCLoopers::generateEvent() +{ + // Clear the vector of pairs + mGenPairs.clear(); + // Clear the vector of compton electrons + mGenElectrons.clear(); + if (mFlatGas) { + unsigned int nLoopers, nLoopersPairs, nLoopersCompton; + LOG(debug) << "mCurrentEvent is " << mCurrentEvent; + LOG(debug) << "Current event time: " << ((mCurrentEvent < mInteractionTimeRecords.size() - 1) ? std::to_string(mInteractionTimeRecords[mCurrentEvent + 1].bc2ns() - mInteractionTimeRecords[mCurrentEvent].bc2ns()) : std::to_string(mTimeEnd - mInteractionTimeRecords[mCurrentEvent].bc2ns())) << " ns"; + LOG(debug) << "Current time offset wrt BC: " << mInteractionTimeRecords[mCurrentEvent].getTimeOffsetWrtBC() << " ns"; + mTimeLimit = (mCurrentEvent < mInteractionTimeRecords.size() - 1) ? mInteractionTimeRecords[mCurrentEvent + 1].bc2ns() - mInteractionTimeRecords[mCurrentEvent].bc2ns() : mTimeEnd - mInteractionTimeRecords[mCurrentEvent].bc2ns(); + // With flat gas the number of loopers are adapted based on time interval widths + nLoopers = mFlatGasNumber * (mTimeLimit / mIntTimeRecMean); + nLoopersPairs = static_cast(std::round(nLoopers * mLoopsFractionPairs)); + nLoopersCompton = nLoopers - nLoopersPairs; + SetNLoopers(nLoopersPairs, nLoopersCompton); + LOG(info) << "Flat gas loopers: " << nLoopers << " (pairs: " << nLoopersPairs << ", compton: " << nLoopersCompton << ")"; + generateEvent(mTimeLimit); + mCurrentEvent++; + } else { + // Set number of loopers if poissonian params are available + if (mPoissonSet) { + mNLoopersPairs = static_cast(std::round(mMultiplier[0] * PoissonPairs())); + } + if (mGaussSet) { + mNLoopersCompton = static_cast(std::round(mMultiplier[1] * GaussianElectrons())); + } + // Generate pairs + for (int i = 0; i < mNLoopersPairs; ++i) { + std::vector pair = mONNX_pair->generate_sample(); + // Apply the inverse transformation using the scaler + std::vector transformed_pair = mScaler_pair->inverse_transform(pair); + mGenPairs.push_back(transformed_pair); + } + // Generate compton electrons + for (int i = 0; i < mNLoopersCompton; ++i) { + std::vector electron = mONNX_compton->generate_sample(); + // Apply the inverse transformation using the scaler + std::vector transformed_electron = mScaler_compton->inverse_transform(electron); + mGenElectrons.push_back(transformed_electron); + } + } + return true; +} + +Bool_t GenTPCLoopers::generateEvent(double& time_limit) +{ + LOG(info) << "Time constraint for loopers: " << time_limit << " ns"; + // Generate pairs + for (int i = 0; i < mNLoopersPairs; ++i) { + std::vector pair = mONNX_pair->generate_sample(); + // Apply the inverse transformation using the scaler + std::vector transformed_pair = mScaler_pair->inverse_transform(pair); + transformed_pair[9] = gRandom->Uniform(0., time_limit); // Regenerate time, scaling is not needed because time_limit is already in nanoseconds + mGenPairs.push_back(transformed_pair); + } + // Generate compton electrons + for (int i = 0; i < mNLoopersCompton; ++i) { + std::vector electron = mONNX_compton->generate_sample(); + // Apply the inverse transformation using the scaler + std::vector transformed_electron = mScaler_compton->inverse_transform(electron); + transformed_electron[6] = gRandom->Uniform(0., time_limit); // Regenerate time, scaling is not needed because time_limit is already in nanoseconds + mGenElectrons.push_back(transformed_electron); + } + LOG(info) << "Generated Particles with time limit"; + return true; +} + +std::vector GenTPCLoopers::importParticles() +{ + std::vector particles; + // Get looper pairs from the event + for (auto& pair : mGenPairs) { + double px_e, py_e, pz_e, px_p, py_p, pz_p; + double vx, vy, vz, time; + double e_etot, p_etot; + px_e = pair[0]; + py_e = pair[1]; + pz_e = pair[2]; + px_p = pair[3]; + py_p = pair[4]; + pz_p = pair[5]; + vx = pair[6]; + vy = pair[7]; + vz = pair[8]; + time = pair[9]; + e_etot = TMath::Sqrt(px_e * px_e + py_e * py_e + pz_e * pz_e + mMass_e * mMass_e); + p_etot = TMath::Sqrt(px_p * px_p + py_p * py_p + pz_p * pz_p + mMass_p * mMass_p); + // Push the electron + TParticle electron(11, 1, -1, -1, -1, -1, px_e, py_e, pz_e, e_etot, vx, vy, vz, time / 1e9); + electron.SetStatusCode(o2::mcgenstatus::MCGenStatusEncoding(electron.GetStatusCode(), 0).fullEncoding); + electron.SetBit(ParticleStatus::kToBeDone, // + o2::mcgenstatus::getHepMCStatusCode(electron.GetStatusCode()) == 1); + particles.push_back(electron); + // Push the positron + TParticle positron(-11, 1, -1, -1, -1, -1, px_p, py_p, pz_p, p_etot, vx, vy, vz, time / 1e9); + positron.SetStatusCode(o2::mcgenstatus::MCGenStatusEncoding(positron.GetStatusCode(), 0).fullEncoding); + positron.SetBit(ParticleStatus::kToBeDone, // + o2::mcgenstatus::getHepMCStatusCode(positron.GetStatusCode()) == 1); + particles.push_back(positron); + } + // Get compton electrons from the event + for (auto& compton : mGenElectrons) { + double px, py, pz; + double vx, vy, vz, time; + double etot; + px = compton[0]; + py = compton[1]; + pz = compton[2]; + vx = compton[3]; + vy = compton[4]; + vz = compton[5]; + time = compton[6]; + etot = TMath::Sqrt(px * px + py * py + pz * pz + mMass_e * mMass_e); + // Push the electron + TParticle electron(11, 1, -1, -1, -1, -1, px, py, pz, etot, vx, vy, vz, time / 1e9); + electron.SetStatusCode(o2::mcgenstatus::MCGenStatusEncoding(electron.GetStatusCode(), 0).fullEncoding); + electron.SetBit(ParticleStatus::kToBeDone, // + o2::mcgenstatus::getHepMCStatusCode(electron.GetStatusCode()) == 1); + particles.push_back(electron); + } + + return particles; +} + +unsigned int GenTPCLoopers::PoissonPairs() +{ + unsigned int poissonValue; + do { + // Generate a Poisson-distributed random number with mean mPoisson[0] + poissonValue = mRandGen.Poisson(mPoisson[0]); + } while (poissonValue < mPoisson[1] || poissonValue > mPoisson[2]); // Regenerate if out of range + + return poissonValue; +} + +unsigned int GenTPCLoopers::GaussianElectrons() +{ + unsigned int gaussValue; + do { + // Generate a Normal-distributed random number with mean mGass[0] and stddev mGauss[1] + gaussValue = mRandGen.Gaus(mGauss[0], mGauss[1]); + } while (gaussValue < mGauss[2] || gaussValue > mGauss[3]); // Regenerate if out of range + + return gaussValue; +} + +void GenTPCLoopers::SetNLoopers(unsigned int& nsig_pair, unsigned int& nsig_compton) +{ + if (mFlatGas) { + mNLoopersPairs = nsig_pair; + mNLoopersCompton = nsig_compton; + } else { + if (mPoissonSet) { + LOG(info) << "Poissonian parameters correctly loaded."; + } else { + mNLoopersPairs = nsig_pair; + } + if (mGaussSet) { + LOG(info) << "Gaussian parameters correctly loaded."; + } else { + mNLoopersCompton = nsig_compton; + } + } +} + +void GenTPCLoopers::SetMultiplier(std::array& mult) +{ + // Multipliers will work only if the poissonian and gaussian parameters are set + // otherwise they will be ignored + if (mult[0] < 0 || mult[1] < 0) + { + LOG(fatal) << "Error: Multiplier values must be non-negative!"; + exit(1); + } else { + LOG(info) << "Multiplier values set to: Pair = " << mult[0] << ", Compton = " << mult[1]; + mMultiplier[0] = mult[0]; + mMultiplier[1] = mult[1]; + } +} + +void GenTPCLoopers::setFlatGas(Bool_t& flat, const Int_t& number) +{ + mFlatGas = flat; + if (mFlatGas) { + if (number < 0) { + LOG(warn) << "Warning: Number of loopers per event must be non-negative! Switching option off."; + mFlatGas = false; + mFlatGasNumber = -1; + } else { + mFlatGasNumber = number; + mContextFile = std::filesystem::exists("collisioncontext.root") ? TFile::Open("collisioncontext.root") : nullptr; + mCollisionContext = mContextFile ? (o2::steer::DigitizationContext*)mContextFile->Get("DigitizationContext") : nullptr; + mInteractionTimeRecords = mCollisionContext ? mCollisionContext->getEventRecords() : std::vector{}; + if (mInteractionTimeRecords.empty()) { + LOG(error) << "Error: No interaction time records found in the collision context!"; + exit(1); + } else { + LOG(info) << "Interaction Time records has " << mInteractionTimeRecords.size() << " entries."; + mCollisionContext->printCollisionSummary(); + } + for (int c = 0; c < mInteractionTimeRecords.size() - 1; c++) { + mIntTimeRecMean += mInteractionTimeRecords[c + 1].bc2ns() - mInteractionTimeRecords[c].bc2ns(); + } + mIntTimeRecMean /= (mInteractionTimeRecords.size() - 1); // Average interaction time record used as reference + const auto& hbfUtils = o2::raw::HBFUtils::Instance(); + // Get the start time of the second orbit after the last interaction record + const auto& lastIR = mInteractionTimeRecords.back(); + o2::InteractionRecord finalOrbitIR(0, lastIR.orbit + 2); // Final orbit, BC = 0 + mTimeEnd = finalOrbitIR.bc2ns(); + LOG(debug) << "Final orbit start time: " << mTimeEnd << " ns while last interaction record time is " << mInteractionTimeRecords.back().bc2ns() << " ns"; + } + } else { + mFlatGasNumber = -1; + } + LOG(info) << "Flat gas loopers: " << (mFlatGas ? "ON" : "OFF") << ", Reference loopers number per event: " << mFlatGasNumber; +} + +void GenTPCLoopers::setFractionPairs(float& fractionPairs) +{ + if (fractionPairs < 0 || fractionPairs > 1) { + LOG(fatal) << "Error: Loops fraction for pairs must be in the range [0, 1]."; + exit(1); + } + mLoopsFractionPairs = fractionPairs; + LOG(info) << "Pairs fraction set to: " << mLoopsFractionPairs; +} + +} // namespace eventgen +} // namespace o2 \ No newline at end of file diff --git a/Generators/src/TPCLoopersParam.cxx b/Generators/src/TPCLoopersParam.cxx new file mode 100644 index 0000000000000..0202a8ced0535 --- /dev/null +++ b/Generators/src/TPCLoopersParam.cxx @@ -0,0 +1,15 @@ +// Copyright 2024-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author M+Giacalone - September 2025 + +#include "Generators/TPCLoopersParam.h" +O2ParamImpl(o2::eventgen::GenTPCLoopersParam); From 4b6530fbc6a93963de72035d123b6666b2991e32 Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Fri, 26 Sep 2025 15:57:46 +0200 Subject: [PATCH 034/234] Various improvements Fixed arrays in TPCLoopersParams and implemented comments --- .../SimConfig/include/SimConfig/SimConfig.h | 3 - Common/SimConfig/src/SimConfig.cxx | 2 - Generators/CMakeLists.txt | 4 +- Generators/include/Generators/Generator.h | 11 +- .../include/Generators/TPCLoopersParam.h | 5 +- Generators/include/TPCLoopers.h | 12 +- Generators/src/Generator.cxx | 392 +++++++++--------- Generators/src/GeneratorsLinkDef.h | 2 +- Generators/src/TPCLoopers.cxx | 3 - 9 files changed, 214 insertions(+), 220 deletions(-) diff --git a/Common/SimConfig/include/SimConfig/SimConfig.h b/Common/SimConfig/include/SimConfig/SimConfig.h index 8642a0e5bc225..be88d9fbd8c33 100644 --- a/Common/SimConfig/include/SimConfig/SimConfig.h +++ b/Common/SimConfig/include/SimConfig/SimConfig.h @@ -52,7 +52,6 @@ struct SimConfigData { std::vector mActiveModules; // list of active modules std::vector mReadoutDetectors; // list of readout detectors std::string mMCEngine; // chosen VMC engine - bool mNoLoopers = false; // Disable automatic TPC loopers std::string mGenerator; // chosen VMC generator std::string mTrigger; // chosen VMC generator trigger unsigned int mNEvents; // number of events to be simulated @@ -139,8 +138,6 @@ class SimConfig // get selected active detectors std::vector const& getActiveModules() const { return mConfigData.mActiveModules; } std::vector const& getReadoutDetectors() const { return mConfigData.mReadoutDetectors; } - // get loopers veto - bool getLoopersVeto() const { return mConfigData.mNoLoopers; } // static helper functions to determine list of active / readout modules // can also be used from outside diff --git a/Common/SimConfig/src/SimConfig.cxx b/Common/SimConfig/src/SimConfig.cxx index 5ddc3199e3d4a..15879687872d5 100644 --- a/Common/SimConfig/src/SimConfig.cxx +++ b/Common/SimConfig/src/SimConfig.cxx @@ -74,7 +74,6 @@ void SimConfig::initOptions(boost::program_options::options_description& options "run", bpo::value()->default_value(-1), "ALICE run number")( "asservice", bpo::value()->default_value(false), "run in service/server mode")( "noGeant", bpo::bool_switch(), "prohibits any Geant transport/physics (by using tight cuts)")( - "noLoopers", bpo::bool_switch(), "disable automatic TPC loopers")( "forwardKine", bpo::bool_switch(), "forward kinematics on a FairMQ channel")( "noDiscOutput", bpo::bool_switch(), "switch off writing sim results to disc (useful in combination with forwardKine)"); options.add_options()("fromCollContext", bpo::value()->default_value(""), "Use a pregenerated collision context to infer number of events to simulate, how to embedd them, the vertex position etc. Takes precedence of other options such as \"--nEvents\". The format is COLLISIONCONTEXTFILE.root[:SIGNALNAME] where SIGNALNAME is the event part in the context which is relevant."); @@ -298,7 +297,6 @@ bool SimConfig::resetFromParsedMap(boost::program_options::variables_map const& using o2::detectors::DetID; mConfigData.mMCEngine = vm["mcEngine"].as(); mConfigData.mNoGeant = vm["noGeant"].as(); - mConfigData.mNoLoopers = vm["noLoopers"].as(); // Reset modules and detectors as they are anyway re-parsed mConfigData.mReadoutDetectors.clear(); diff --git a/Generators/CMakeLists.txt b/Generators/CMakeLists.txt index 56fe8b8fc2284..f1921b8d8d72a 100644 --- a/Generators/CMakeLists.txt +++ b/Generators/CMakeLists.txt @@ -67,7 +67,7 @@ if(HepMC3_FOUND) endif() if(onnxruntime_FOUND) - target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_ONNXRUNTIME) + target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_TPCLOOPERS) endif() set(headers @@ -96,7 +96,7 @@ set(headers ) if(onnxruntime_FOUND) - list(APPEND headers + list(APPEND headers include/Generators/TPCLoopers.h include/Generators/TPCLoopersParam.h) endif() diff --git a/Generators/include/Generators/Generator.h b/Generators/include/Generators/Generator.h index 374d53f324399..4b68112517893 100644 --- a/Generators/include/Generators/Generator.h +++ b/Generators/include/Generators/Generator.h @@ -17,7 +17,8 @@ #include "FairGenerator.h" #include "TParticle.h" #include "Generators/Trigger.h" -#ifdef GENERATORS_WITH_ONNXRUNTIME +#include "CCDB/BasicCCDBManager.h" +#ifdef GENERATORS_WITH_TPCLOOPERS #include "Generators/TPCLoopers.h" #include "Generators/TPCLoopersParam.h" #endif @@ -77,7 +78,7 @@ class Generator : public FairGenerator /** methods to override **/ virtual Bool_t generateEvent() = 0; // generates event (in structure internal to generator) virtual Bool_t importParticles() = 0; // fills the mParticles vector (transfer from generator state) - Bool_t loopers(); // adds loopers to the event in case TPC is used + Bool_t finalizeEvent(); // final part of event generation that can be customised using external macros virtual void updateHeader(o2::dataformats::MCEventHeader* eventHeader) {}; Bool_t triggerEvent(); @@ -160,7 +161,7 @@ class Generator : public FairGenerator void updateSubGeneratorInformation(o2::dataformats::MCEventHeader* header) const; // loopers flag - Bool_t mAddLoopers = kFALSE; + Bool_t mAddTPCLoopers = kFALSE; // Flag is automatically set to true if TPC is in readout detectors, loopers are not vetoed and transport is enabled // collect an ID and a short description of sub-generator entities std::unordered_map mSubGeneratorsIdToDesc; // the current ID of the sub-generator used in the current event (if applicable) @@ -169,11 +170,11 @@ class Generator : public FairGenerator // global static information about (upper limit of) number of events to be generated static unsigned int gTotalNEvents; -#ifdef GENERATORS_WITH_ONNXRUNTIME +#ifdef GENERATORS_WITH_TPCLOOPERS // Loopers generator instance std::unique_ptr mLoopersGen = nullptr; -#endif void initLoopersGen(); +#endif ClassDefOverride(Generator, 2); diff --git a/Generators/include/Generators/TPCLoopersParam.h b/Generators/include/Generators/TPCLoopersParam.h index ceeea201538b2..9430f4e05ac6e 100644 --- a/Generators/include/Generators/TPCLoopersParam.h +++ b/Generators/include/Generators/TPCLoopersParam.h @@ -28,6 +28,7 @@ namespace eventgen ** allow the user to modify them **/ struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper { + bool loopersVeto = false; // if true, no loopers are generated std::string model_pairs = "ccdb://Users/m/mgiacalo/WGAN_ExtGenPair"; // ONNX model for e+e- pair production std::string model_compton = "ccdb://Users/m/mgiacalo/WGAN_ExtGenCompton"; // ONNX model for Compton scattering std::string poisson = "${O2_ROOT}/share/Generators/egconfig/poisson_params.csv"; // file with Poissonian parameters @@ -37,8 +38,8 @@ struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper multiplier = {1., 1.}; // multiplier for pairs and compton loopers for Poissonian and Gaussian sampling - std::array fixedNLoopers = {1, 1}; // fixed number of loopers coming from pairs and compton electrons - valid if flat gas is false and both Poisson and Gaussian params files are empty + float multiplier[2] = {1., 1.}; // multiplier for pairs and compton loopers for Poissonian and Gaussian sampling + unsigned int fixedNLoopers[2] = {1, 1}; // fixed number of loopers coming from pairs and compton electrons - valid if flat gas is false and both Poisson and Gaussian params files are empty O2ParamDef(GenTPCLoopersParam, "GenTPCLoopers"); }; diff --git a/Generators/include/TPCLoopers.h b/Generators/include/TPCLoopers.h index 70146a82baf60..1c1f3585eb3ab 100644 --- a/Generators/include/TPCLoopers.h +++ b/Generators/include/TPCLoopers.h @@ -1,7 +1,7 @@ #ifndef ALICEO2_EVENTGEN_TPCLOOPERS_H_ #define ALICEO2_EVENTGEN_TPCLOOPERS_H_ -#ifdef GENERATORS_WITH_ONNXRUNTIME +#ifdef GENERATORS_WITH_TPCLOOPERS #include #endif #include @@ -19,12 +19,10 @@ #include "TParticle.h" #include -#ifdef GENERATORS_WITH_ONNXRUNTIME +#ifdef GENERATORS_WITH_TPCLOOPERS // Static Ort::Env instance for multiple onnx model loading extern Ort::Env global_env; -#endif -#ifdef GENERATORS_WITH_ONNXRUNTIME // This class is responsible for loading the scaler parameters from a JSON file // and applying the inverse transformation to the generated data. struct Scaler @@ -55,14 +53,14 @@ class ONNXGenerator Ort::Session session; TRandom3 rand_gen; }; -#endif // GENERATORS_WITH_ONNXRUNTIME +#endif // GENERATORS_WITH_TPCLOOPERS namespace o2 { namespace eventgen { -#ifdef GENERATORS_WITH_ONNXRUNTIME +#ifdef GENERATORS_WITH_TPCLOOPERS class GenTPCLoopers { public: @@ -119,7 +117,7 @@ class GenTPCLoopers double mTimeEnd = 0.0; // Time limit for the last event float mLoopsFractionPairs = 0.08; // Fraction of loopers from Pairs }; -#endif // GENERATORS_WITH_ONNXRUNTIME +#endif // GENERATORS_WITH_TPCLOOPERS } // namespace eventgen } // namespace o2 diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 153ef5cd5e35e..6fc9f378148d3 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -42,18 +42,20 @@ Generator::Generator() : FairGenerator("ALICEo2", "ALICEo2 Generator"), /** default constructor **/ mThisInstanceID = Generator::InstanceCounter; Generator::InstanceCounter++; - auto simConfig = o2::conf::SimConfig::Instance(); - auto noLoops = simConfig.getLoopersVeto(); - if (!noLoops) { +#ifdef GENERATORS_WITH_TPCLOOPERS + const auto& simConfig = o2::conf::SimConfig::Instance(); + const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); + if (!loopersParam.loopersVeto) { bool transport = (simConfig.getMCEngine() != "O2TrivialMCEngine"); if (transport) { bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); if (tpcActive) { - mAddLoopers = kTRUE; + mAddTPCLoopers = kTRUE; initLoopersGen(); } } } +#endif } /*****************************************************************/ @@ -64,25 +66,26 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na /** constructor **/ mThisInstanceID = Generator::InstanceCounter; Generator::InstanceCounter++; - auto simConfig = o2::conf::SimConfig::Instance(); - auto noLoops = simConfig.getLoopersVeto(); - if (!noLoops) { +#ifdef GENERATORS_WITH_TPCLOOPERS + const auto& simConfig = o2::conf::SimConfig::Instance(); + const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); + if (!loopersParam.loopersVeto) { bool transport = (simConfig.getMCEngine() != "O2TrivialMCEngine"); if (transport) { bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); if (tpcActive) { - mAddLoopers = kTRUE; + mAddTPCLoopers = kTRUE; initLoopersGen(); } } } +#endif } /*****************************************************************/ - +#ifdef GENERATORS_WITH_TPCLOOPERS void Generator::initLoopersGen() { -#ifdef GENERATORS_WITH_ONNXRUNTIME // Expand all environment paths const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); std::string model_pairs = gSystem->ExpandPathName(loopersParam.model_pairs.c_str()); @@ -94,8 +97,9 @@ void Generator::initLoopersGen() auto flat_gas = loopersParam.flat_gas; const auto& nFlatGasLoopers = loopersParam.nFlatGasLoopers; auto fraction_pairs = loopersParam.fraction_pairs; - auto multiplier = loopersParam.multiplier; - auto fixedNLoopers = loopersParam.fixedNLoopers; + std::array multiplier = {loopersParam.multiplier[0], loopersParam.multiplier[1]}; + unsigned int nLoopersPairs = loopersParam.fixedNLoopers[0]; + unsigned int nLoopersCompton = loopersParam.fixedNLoopers[1]; const std::array models = {model_pairs, model_compton}; const std::array local_names = {"WGANpair.onnx", "WGANcompton.onnx"}; const std::array isAlien = {models[0].starts_with("alien://"), models[1].starts_with("alien://")}; @@ -116,8 +120,10 @@ void Generator::initLoopersGen() } } if (std::any_of(isCCDB.begin(), isCCDB.end(), [](bool v) { return v; })) { - o2::ccdb::CcdbApi ccdb_api; - ccdb_api.init("http://alice-ccdb.cern.ch"); + auto& ccdb = o2::ccdb::BasicCCDBManager::instance(); + ccdb.setURL("http://alice-ccdb.cern.ch"); + // Get underlying CCDB API from BasicCCDBManager + auto& ccdb_api = ccdb.getCCDBAccessor(); for (size_t i = 0; i < models.size(); ++i) { if (isCCDB[i]) { auto model_path = models[i].substr(7); // Remove "ccdb://" @@ -149,7 +155,7 @@ void Generator::initLoopersGen() // Otherwise, Poisson+Gauss sampling or fixed number of loopers will be used // Multiplier is applied only with distribution sampling // This configuration can be used for testing purposes, in all other cases flat gas is recommended - mLoopersGen->SetNLoopers(fixedNLoopers[0], fixedNLoopers[1]); + mLoopersGen->SetNLoopers(nLoopersPairs, nLoopersCompton); mLoopersGen->SetMultiplier(multiplier); } LOG(info) << "TPC Loopers generator initialized successfully"; @@ -157,10 +163,8 @@ void Generator::initLoopersGen() LOG(error) << "Failed to initialize TPC Loopers generator: " << e.what(); mLoopersGen.reset(); } -#else - LOG(warn) << "ONNX Runtime support not available, cannot initialize TPC loopers generator"; -#endif } +#endif /*****************************************************************/ @@ -176,230 +180,228 @@ Bool_t /*****************************************************************/ Bool_t - Generator::loopers() + Generator::finalizeEvent() { -#ifdef GENERATORS_WITH_ONNXRUNTIME - if (!mLoopersGen) { - LOG(error) << "Loopers generator not initialized"; - return kFALSE; - } +#ifdef GENERATORS_WITH_TPCLOOPERS + if(mAddTPCLoopers) { + if (!mLoopersGen) { + LOG(error) << "Loopers generator not initialized"; + return kFALSE; + } - // Generate loopers using the initialized TPC loopers generator - if (!mLoopersGen->generateEvent()) { - LOG(error) << "Failed to generate loopers event"; - return kFALSE; - } - const auto& looperParticles = mLoopersGen->importParticles(); - if (looperParticles.empty()) { - LOG(error) << "Failed to import loopers particles"; - return kFALSE; - } - // Append the generated looper particles to the main particle list - mParticles.insert(mParticles.end(), looperParticles.begin(), looperParticles.end()); + // Generate loopers using the initialized TPC loopers generator + if (!mLoopersGen->generateEvent()) { + LOG(error) << "Failed to generate loopers event"; + return kFALSE; + } + const auto& looperParticles = mLoopersGen->importParticles(); + if (looperParticles.empty()) { + LOG(error) << "Failed to import loopers particles"; + return kFALSE; + } + // Append the generated looper particles to the main particle list + mParticles.insert(mParticles.end(), looperParticles.begin(), looperParticles.end()); - LOG(debug) << "Added " << looperParticles.size() << " looper particles"; - return kTRUE; -#else - LOG(warn) << "ONNX Runtime support not available, skipping TPC loopers generation"; - return kTRUE; + LOG(debug) << "Added " << looperParticles.size() << " looper particles"; + } #endif + return kTRUE; } - /*****************************************************************/ - Bool_t - Generator::ReadEvent(FairPrimaryGenerator * primGen) - { - /** read event **/ - - /** endless generate-and-trigger loop **/ - while (true) { - mReadEventCounter++; +/*****************************************************************/ - /** clear particle vector **/ - mParticles.clear(); +Bool_t + Generator::ReadEvent(FairPrimaryGenerator* primGen) +{ + /** read event **/ - /** reset the sub-generator ID **/ - mSubGeneratorId = -1; + /** endless generate-and-trigger loop **/ + while (true) { + mReadEventCounter++; - /** generate event **/ - if (!generateEvent()) { - LOG(error) << "ReadEvent failed in generateEvent"; - return kFALSE; - } + /** clear particle vector **/ + mParticles.clear(); - /** import particles **/ - if (!importParticles()) { - LOG(error) << "ReadEvent failed in importParticles"; - return kFALSE; - } + /** reset the sub-generator ID **/ + mSubGeneratorId = -1; - /** Add loopers **/ - if(mAddLoopers){ - if (!loopers()) { - LOG(error) << "ReadEvent failed in loopers"; - return kFALSE; - } - } + /** generate event **/ + if (!generateEvent()) { + LOG(error) << "ReadEvent failed in generateEvent"; + return kFALSE; + } - if (mSubGeneratorsIdToDesc.empty() && mSubGeneratorId > -1) { - LOG(fatal) << "ReadEvent failed because no SubGenerator description given"; - } + /** import particles **/ + if (!importParticles()) { + LOG(error) << "ReadEvent failed in importParticles"; + return kFALSE; + } - if (!mSubGeneratorsIdToDesc.empty() && mSubGeneratorId < 0) { - LOG(fatal) << "ReadEvent failed because SubGenerator description given but sub-generator not set"; - } + /** Event finalization**/ + if(!finalizeEvent()) { + LOG(error) << "ReadEvent failed in finalizeEvent"; + return kFALSE; + } - /** trigger event **/ - if (triggerEvent()) { - mTriggerOkHook(mParticles, mReadEventCounter); - break; - } else { - mTriggerFalseHook(mParticles, mReadEventCounter); - } + if (mSubGeneratorsIdToDesc.empty() && mSubGeneratorId > -1) { + LOG(fatal) << "ReadEvent failed because no SubGenerator description given"; } - /** add tracks **/ - if (!addTracks(primGen)) { - LOG(error) << "ReadEvent failed in addTracks"; - return kFALSE; + if (!mSubGeneratorsIdToDesc.empty() && mSubGeneratorId < 0) { + LOG(fatal) << "ReadEvent failed because SubGenerator description given but sub-generator not set"; } - /** update header **/ - auto header = primGen->GetEvent(); - auto o2header = dynamic_cast(header); - if (!header) { - LOG(fatal) << "MC event header is not a 'o2::dataformats::MCEventHeader' object"; - return kFALSE; + /** trigger event **/ + if (triggerEvent()) { + mTriggerOkHook(mParticles, mReadEventCounter); + break; + } else { + mTriggerFalseHook(mParticles, mReadEventCounter); } - updateHeader(o2header); - updateSubGeneratorInformation(o2header); + } - /** success **/ - return kTRUE; + /** add tracks **/ + if (!addTracks(primGen)) { + LOG(error) << "ReadEvent failed in addTracks"; + return kFALSE; + } + + /** update header **/ + auto header = primGen->GetEvent(); + auto o2header = dynamic_cast(header); + if (!header) { + LOG(fatal) << "MC event header is not a 'o2::dataformats::MCEventHeader' object"; + return kFALSE; } + updateHeader(o2header); + updateSubGeneratorInformation(o2header); - /*****************************************************************/ + /** success **/ + return kTRUE; +} - Bool_t - Generator::addTracks(FairPrimaryGenerator * primGen) - { - /** add tracks **/ +/*****************************************************************/ - auto o2primGen = dynamic_cast(primGen); - if (!o2primGen) { - LOG(fatal) << "PrimaryGenerator is not a o2::eventgen::PrimaryGenerator"; - return kFALSE; - } +Bool_t + Generator::addTracks(FairPrimaryGenerator* primGen) +{ + /** add tracks **/ - /** loop over particles **/ - for (const auto& particle : mParticles) { - o2primGen->AddTrack(particle.GetPdgCode(), - particle.Px() * mMomentumUnit, - particle.Py() * mMomentumUnit, - particle.Pz() * mMomentumUnit, - particle.Vx() * mPositionUnit, - particle.Vy() * mPositionUnit, - particle.Vz() * mPositionUnit, - particle.GetMother(0), - particle.GetMother(1), - particle.GetDaughter(0), - particle.GetDaughter(1), - particle.TestBit(ParticleStatus::kToBeDone), - particle.Energy() * mEnergyUnit, - particle.T() * mTimeUnit, - particle.GetWeight(), - (TMCProcess)particle.GetUniqueID(), - particle.GetStatusCode()); // generator status information passed as status code field - } + auto o2primGen = dynamic_cast(primGen); + if (!o2primGen) { + LOG(fatal) << "PrimaryGenerator is not a o2::eventgen::PrimaryGenerator"; + return kFALSE; + } - /** success **/ - return kTRUE; + /** loop over particles **/ + for (const auto& particle : mParticles) { + o2primGen->AddTrack(particle.GetPdgCode(), + particle.Px() * mMomentumUnit, + particle.Py() * mMomentumUnit, + particle.Pz() * mMomentumUnit, + particle.Vx() * mPositionUnit, + particle.Vy() * mPositionUnit, + particle.Vz() * mPositionUnit, + particle.GetMother(0), + particle.GetMother(1), + particle.GetDaughter(0), + particle.GetDaughter(1), + particle.TestBit(ParticleStatus::kToBeDone), + particle.Energy() * mEnergyUnit, + particle.T() * mTimeUnit, + particle.GetWeight(), + (TMCProcess)particle.GetUniqueID(), + particle.GetStatusCode()); // generator status information passed as status code field } - /*****************************************************************/ + /** success **/ + return kTRUE; +} + +/*****************************************************************/ - Bool_t - Generator::boostEvent() - { - /** boost event **/ +Bool_t + Generator::boostEvent() +{ + /** boost event **/ + + /** success **/ + return kTRUE; +} + +/*****************************************************************/ + +Bool_t + Generator::triggerEvent() +{ + /** trigger event **/ - /** success **/ + /** check trigger presence **/ + if (mTriggers.size() == 0 && mDeepTriggers.size() == 0) { return kTRUE; } - /*****************************************************************/ - - Bool_t - Generator::triggerEvent() - { - /** trigger event **/ + /** check trigger mode **/ + Bool_t triggered; + if (mTriggerMode == kTriggerOFF) { + return kTRUE; + } else if (mTriggerMode == kTriggerOR) { + triggered = kFALSE; + } else if (mTriggerMode == kTriggerAND) { + triggered = kTRUE; + } else { + return kTRUE; + } - /** check trigger presence **/ - if (mTriggers.size() == 0 && mDeepTriggers.size() == 0) { - return kTRUE; + /** loop over triggers **/ + for (const auto& trigger : mTriggers) { + auto retval = trigger(mParticles); + if (mTriggerMode == kTriggerOR) { + triggered |= retval; } - - /** check trigger mode **/ - Bool_t triggered; - if (mTriggerMode == kTriggerOFF) { - return kTRUE; - } else if (mTriggerMode == kTriggerOR) { - triggered = kFALSE; - } else if (mTriggerMode == kTriggerAND) { - triggered = kTRUE; - } else { - return kTRUE; + if (mTriggerMode == kTriggerAND) { + triggered &= retval; } + } - /** loop over triggers **/ - for (const auto& trigger : mTriggers) { - auto retval = trigger(mParticles); - if (mTriggerMode == kTriggerOR) { - triggered |= retval; - } - if (mTriggerMode == kTriggerAND) { - triggered &= retval; - } + /** loop over deep triggers **/ + for (const auto& trigger : mDeepTriggers) { + auto retval = trigger(mInterface, mInterfaceName); + if (mTriggerMode == kTriggerOR) { + triggered |= retval; } - - /** loop over deep triggers **/ - for (const auto& trigger : mDeepTriggers) { - auto retval = trigger(mInterface, mInterfaceName); - if (mTriggerMode == kTriggerOR) { - triggered |= retval; - } - if (mTriggerMode == kTriggerAND) { - triggered &= retval; - } + if (mTriggerMode == kTriggerAND) { + triggered &= retval; } - - /** return **/ - return triggered; } - /*****************************************************************/ + /** return **/ + return triggered; +} - void Generator::addSubGenerator(int subGeneratorId, std::string const& subGeneratorDescription) - { - if (subGeneratorId < 0) { - LOG(fatal) << "Sub-generator IDs must be >= 0, instead, passed value is " << subGeneratorId; - } - mSubGeneratorsIdToDesc.insert({subGeneratorId, subGeneratorDescription}); +/*****************************************************************/ + +void Generator::addSubGenerator(int subGeneratorId, std::string const& subGeneratorDescription) +{ + if (subGeneratorId < 0) { + LOG(fatal) << "Sub-generator IDs must be >= 0, instead, passed value is " << subGeneratorId; } + mSubGeneratorsIdToDesc.insert({subGeneratorId, subGeneratorDescription}); +} - /*****************************************************************/ +/*****************************************************************/ - void Generator::updateSubGeneratorInformation(o2::dataformats::MCEventHeader * header) const - { - if (mSubGeneratorId < 0) { - return; - } - header->putInfo(o2::mcgenid::GeneratorProperty::SUBGENERATORID, mSubGeneratorId); - header->putInfo>(o2::mcgenid::GeneratorProperty::SUBGENERATORDESCRIPTIONMAP, mSubGeneratorsIdToDesc); +void Generator::updateSubGeneratorInformation(o2::dataformats::MCEventHeader* header) const +{ + if (mSubGeneratorId < 0) { + return; } + header->putInfo(o2::mcgenid::GeneratorProperty::SUBGENERATORID, mSubGeneratorId); + header->putInfo>(o2::mcgenid::GeneratorProperty::SUBGENERATORDESCRIPTIONMAP, mSubGeneratorsIdToDesc); +} - /*****************************************************************/ - /*****************************************************************/ +/*****************************************************************/ +/*****************************************************************/ } /* namespace eventgen */ } /* namespace o2 */ diff --git a/Generators/src/GeneratorsLinkDef.h b/Generators/src/GeneratorsLinkDef.h index 97896d8225042..24b3f2e452498 100644 --- a/Generators/src/GeneratorsLinkDef.h +++ b/Generators/src/GeneratorsLinkDef.h @@ -35,7 +35,7 @@ #pragma link C++ class o2::eventgen::GeneratorFromEventPool + ; #pragma link C++ class o2::eventgen::GeneratorEventPoolParam + ; #pragma link C++ class o2::eventgen::EventPoolGenConfig + ; -#ifdef GENERATORS_WITH_ONNXRUNTIME +#ifdef GENERATORS_WITH_TPCLOOPERS #pragma link C++ class o2::eventgen::GenTPCLoopers + ; #pragma link C++ class o2::eventgen::GenTPCLoopersParam + ; #endif diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx index 4eacb7674599c..109461ab71dfa 100644 --- a/Generators/src/TPCLoopers.cxx +++ b/Generators/src/TPCLoopers.cxx @@ -382,9 +382,6 @@ void GenTPCLoopers::setFlatGas(Bool_t& flat, const Int_t& number) if (mInteractionTimeRecords.empty()) { LOG(error) << "Error: No interaction time records found in the collision context!"; exit(1); - } else { - LOG(info) << "Interaction Time records has " << mInteractionTimeRecords.size() << " entries."; - mCollisionContext->printCollisionSummary(); } for (int c = 0; c < mInteractionTimeRecords.size() - 1; c++) { mIntTimeRecMean += mInteractionTimeRecords[c + 1].bc2ns() - mInteractionTimeRecords[c].bc2ns(); From 8f8606a66c8499de6df999795d595f3dbab9e5b3 Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Sun, 12 Oct 2025 17:24:31 +0200 Subject: [PATCH 035/234] Vetoing loopers for FlatGas and \!collisioncontext --- Generators/include/Generators/Generator.h | 2 +- Generators/src/Generator.cxx | 21 ++++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Generators/include/Generators/Generator.h b/Generators/include/Generators/Generator.h index 4b68112517893..67277e20736ce 100644 --- a/Generators/include/Generators/Generator.h +++ b/Generators/include/Generators/Generator.h @@ -173,7 +173,7 @@ class Generator : public FairGenerator #ifdef GENERATORS_WITH_TPCLOOPERS // Loopers generator instance std::unique_ptr mLoopersGen = nullptr; - void initLoopersGen(); + bool initLoopersGen(); #endif ClassDefOverride(Generator, 2); diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 6fc9f378148d3..50b11c0c7bb53 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -50,8 +50,9 @@ Generator::Generator() : FairGenerator("ALICEo2", "ALICEo2 Generator"), if (transport) { bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); if (tpcActive) { - mAddTPCLoopers = kTRUE; - initLoopersGen(); + if(initLoopersGen()){ + mAddTPCLoopers = kTRUE; + } } } } @@ -74,8 +75,9 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na if (transport) { bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); if (tpcActive) { - mAddTPCLoopers = kTRUE; - initLoopersGen(); + if (initLoopersGen()) { + mAddTPCLoopers = kTRUE; + } } } } @@ -84,7 +86,7 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na /*****************************************************************/ #ifdef GENERATORS_WITH_TPCLOOPERS -void Generator::initLoopersGen() +bool Generator::initLoopersGen() { // Expand all environment paths const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); @@ -95,6 +97,14 @@ void Generator::initLoopersGen() const auto& poisson = gSystem->ExpandPathName(loopersParam.poisson.c_str()); const auto& gauss = gSystem->ExpandPathName(loopersParam.gauss.c_str()); auto flat_gas = loopersParam.flat_gas; + if (flat_gas) { + bool isContext = std::filesystem::exists("collisioncontext.root"); + if (!isContext) { + LOG(warning) << "Warning: No collisioncontext.root file found!"; + LOG(warning) << "Loopers will be kept OFF."; + return kFALSE; + } + } const auto& nFlatGasLoopers = loopersParam.nFlatGasLoopers; auto fraction_pairs = loopersParam.fraction_pairs; std::array multiplier = {loopersParam.multiplier[0], loopersParam.multiplier[1]}; @@ -163,6 +173,7 @@ void Generator::initLoopersGen() LOG(error) << "Failed to initialize TPC Loopers generator: " << e.what(); mLoopersGen.reset(); } + return kTRUE; } #endif From 32c0f318ec9737e7c1718c373d3c9660ddff477c Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Fri, 24 Oct 2025 16:42:27 +0200 Subject: [PATCH 036/234] Implemented rate and collision system dependence (default) --- .../include/Generators/TPCLoopersParam.h | 4 ++ Generators/include/TPCLoopers.h | 8 ++- Generators/src/Generator.cxx | 28 +++++--- Generators/src/TPCLoopers.cxx | 64 ++++++++++++++++--- 4 files changed, 87 insertions(+), 17 deletions(-) diff --git a/Generators/include/Generators/TPCLoopersParam.h b/Generators/include/Generators/TPCLoopersParam.h index 9430f4e05ac6e..8571013cdec48 100644 --- a/Generators/include/Generators/TPCLoopersParam.h +++ b/Generators/include/Generators/TPCLoopersParam.h @@ -35,11 +35,15 @@ struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper #include "SimulationDataFormat/MCGenProperties.h" #include "TParticle.h" +#include "TF1.h" #include #ifdef GENERATORS_WITH_TPCLOOPERS @@ -82,10 +83,14 @@ class GenTPCLoopers void SetMultiplier(std::array &mult); - void setFlatGas(Bool_t &flat, const Int_t &number = -1); + void setFlatGas(Bool_t& flat, const Int_t& number, const Int_t& nloopers_orbit); void setFractionPairs(float &fractionPairs); + void SetRate(const std::string &rateFile, const bool &isPbPb, const int &intRate); + + void SetAdjust(const float &adjust); + private: std::unique_ptr mONNX_pair = nullptr; std::unique_ptr mONNX_compton = nullptr; @@ -111,6 +116,7 @@ class GenTPCLoopers o2::steer::DigitizationContext *mCollisionContext = nullptr; // Pointer to the digitization context std::vector mInteractionTimeRecords; // Interaction time records from collision context Bool_t mFlatGas = false; // Flag to indicate if flat gas loopers are used + Bool_t mFlatGasOrbit = false; // Flag to indicate if flat gas loopers are per orbit Int_t mFlatGasNumber = -1; // Number of flat gas loopers per event double mIntTimeRecMean = 1.0; // Average interaction time record used for the reference double mTimeLimit = 0.0; // Time limit for the current event diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 50b11c0c7bb53..fea1a38f1a146 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -92,6 +92,7 @@ bool Generator::initLoopersGen() const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); std::string model_pairs = gSystem->ExpandPathName(loopersParam.model_pairs.c_str()); std::string model_compton = gSystem->ExpandPathName(loopersParam.model_compton.c_str()); + std::string nclxrate = gSystem->ExpandPathName(loopersParam.nclxrate.c_str()); const auto& scaler_pair = gSystem->ExpandPathName(loopersParam.scaler_pair.c_str()); const auto& scaler_compton = gSystem->ExpandPathName(loopersParam.scaler_compton.c_str()); const auto& poisson = gSystem->ExpandPathName(loopersParam.poisson.c_str()); @@ -110,10 +111,10 @@ bool Generator::initLoopersGen() std::array multiplier = {loopersParam.multiplier[0], loopersParam.multiplier[1]}; unsigned int nLoopersPairs = loopersParam.fixedNLoopers[0]; unsigned int nLoopersCompton = loopersParam.fixedNLoopers[1]; - const std::array models = {model_pairs, model_compton}; - const std::array local_names = {"WGANpair.onnx", "WGANcompton.onnx"}; - const std::array isAlien = {models[0].starts_with("alien://"), models[1].starts_with("alien://")}; - const std::array isCCDB = {models[0].starts_with("ccdb://"), models[1].starts_with("ccdb://")}; + const std::array models = {model_pairs, model_compton, nclxrate}; + const std::array local_names = {"WGANpair.onnx", "WGANcompton.onnx", "nclxrate.root"}; + const std::array isAlien = {models[0].starts_with("alien://"), models[1].starts_with("alien://"), models[2].starts_with("alien://")}; + const std::array isCCDB = {models[0].starts_with("ccdb://"), models[1].starts_with("ccdb://"), models[2].starts_with("ccdb://")}; if (std::any_of(isAlien.begin(), isAlien.end(), [](bool v) { return v; })) { if (!gGrid) { TGrid::Connect("alien://"); @@ -153,14 +154,25 @@ bool Generator::initLoopersGen() } model_pairs = isAlien[0] || isCCDB[0] ? local_names[0] : model_pairs; model_compton = isAlien[1] || isCCDB[1] ? local_names[1] : model_compton; + nclxrate = isAlien[2] || isCCDB[2] ? local_names[2] : nclxrate; try { // Create the TPC loopers generator with the provided parameters mLoopersGen = std::make_unique(model_pairs, model_compton, poisson, gauss, scaler_pair, scaler_compton); - - // Configure the generator with flat gas loopers if enabled (default) + auto& colsys = loopersParam.colsys; + auto &intrate = loopersParam.intrate; + // Configure the generator with flat gas loopers defined per orbit with clusters/track info if (flat_gas) { - mLoopersGen->setFlatGas(flat_gas, nFlatGasLoopers); - mLoopersGen->setFractionPairs(fraction_pairs); + if (colsys != "PbPb" && colsys != "pp") { + LOG(fatal) << "Error: collision system must be either 'PbPb' or 'pp'"; + exit(1); + } else { + if (intrate <= 0) { + LOG(fatal) << "Error: interaction rate must be positive!"; + exit(1); + } + mLoopersGen->SetRate(nclxrate, (colsys == "PbPb") ? true : false, intrate); + mLoopersGen->SetAdjust(loopersParam.adjust_flatgas); + } } else { // Otherwise, Poisson+Gauss sampling or fixed number of loopers will be used // Multiplier is applied only with distribution sampling diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx index 109461ab71dfa..b771b53ed33d2 100644 --- a/Generators/src/TPCLoopers.cxx +++ b/Generators/src/TPCLoopers.cxx @@ -197,7 +197,8 @@ Bool_t GenTPCLoopers::generateEvent() LOG(debug) << "Current time offset wrt BC: " << mInteractionTimeRecords[mCurrentEvent].getTimeOffsetWrtBC() << " ns"; mTimeLimit = (mCurrentEvent < mInteractionTimeRecords.size() - 1) ? mInteractionTimeRecords[mCurrentEvent + 1].bc2ns() - mInteractionTimeRecords[mCurrentEvent].bc2ns() : mTimeEnd - mInteractionTimeRecords[mCurrentEvent].bc2ns(); // With flat gas the number of loopers are adapted based on time interval widths - nLoopers = mFlatGasNumber * (mTimeLimit / mIntTimeRecMean); + // The denominator is either the LHC orbit (if mFlatGasOrbit is true) or the mean interaction time record interval + nLoopers = mFlatGasOrbit ? (mFlatGasNumber * (mTimeLimit / o2::constants::lhc::LHCOrbitNS)) : (mFlatGasNumber * (mTimeLimit / mIntTimeRecMean)); nLoopersPairs = static_cast(std::round(nLoopers * mLoopsFractionPairs)); nLoopersCompton = nLoopers - nLoopersPairs; SetNLoopers(nLoopersPairs, nLoopersCompton); @@ -366,22 +367,34 @@ void GenTPCLoopers::SetMultiplier(std::array& mult) } } -void GenTPCLoopers::setFlatGas(Bool_t& flat, const Int_t& number) +void GenTPCLoopers::setFlatGas(Bool_t& flat, const Int_t& number = -1, const Int_t& nloopers_orbit = -1) { mFlatGas = flat; if (mFlatGas) { - if (number < 0) { - LOG(warn) << "Warning: Number of loopers per event must be non-negative! Switching option off."; - mFlatGas = false; - mFlatGasNumber = -1; + if (nloopers_orbit > 0) { + mFlatGasOrbit = true; + mFlatGasNumber = nloopers_orbit; + LOG(info) << "Flat gas loopers will be generated using orbit reference."; } else { - mFlatGasNumber = number; + mFlatGasOrbit = false; + if (number < 0) { + LOG(warn) << "Warning: Number of loopers per event must be non-negative! Switching option off."; + mFlatGas = false; + mFlatGasNumber = -1; + } else { + mFlatGasNumber = number; + } + } + if (mFlatGas) { mContextFile = std::filesystem::exists("collisioncontext.root") ? TFile::Open("collisioncontext.root") : nullptr; mCollisionContext = mContextFile ? (o2::steer::DigitizationContext*)mContextFile->Get("DigitizationContext") : nullptr; mInteractionTimeRecords = mCollisionContext ? mCollisionContext->getEventRecords() : std::vector{}; if (mInteractionTimeRecords.empty()) { LOG(error) << "Error: No interaction time records found in the collision context!"; exit(1); + } else { + LOG(info) << "Interaction Time records has " << mInteractionTimeRecords.size() << " entries."; + mCollisionContext->printCollisionSummary(); } for (int c = 0; c < mInteractionTimeRecords.size() - 1; c++) { mIntTimeRecMean += mInteractionTimeRecords[c + 1].bc2ns() - mInteractionTimeRecords[c].bc2ns(); @@ -397,7 +410,7 @@ void GenTPCLoopers::setFlatGas(Bool_t& flat, const Int_t& number) } else { mFlatGasNumber = -1; } - LOG(info) << "Flat gas loopers: " << (mFlatGas ? "ON" : "OFF") << ", Reference loopers number per event: " << mFlatGasNumber; + LOG(info) << "Flat gas loopers: " << (mFlatGas ? "ON" : "OFF") << ", Reference loopers number per " << (mFlatGasOrbit ? "orbit " : "event ") << mFlatGasNumber; } void GenTPCLoopers::setFractionPairs(float& fractionPairs) @@ -410,5 +423,40 @@ void GenTPCLoopers::setFractionPairs(float& fractionPairs) LOG(info) << "Pairs fraction set to: " << mLoopsFractionPairs; } +void GenTPCLoopers::SetRate(const std::string &rateFile, const bool &isPbPb = true, const int &intRate = 50000) +{ + // Checking if the rate file exists and is not empty + TFile rate_file(rateFile.c_str(), "READ"); + if (!rate_file.IsOpen() || rate_file.IsZombie()) { + LOG(fatal) << "Error: Rate file is empty or does not exist!"; + exit(1); + } + const char* fitName = isPbPb ? "fitPbPb" : "fitpp"; + auto fit = (TF1*)rate_file.Get(fitName); + if (!fit) { + LOG(fatal) << "Error: Could not find fit function '" << fitName << "' in rate file!"; + exit(1); + } + auto ref = static_cast(std::floor(fit->Eval(intRate / 1000.))); // fit expects rate in kHz + rate_file.Close(); + if (ref <= 0) { + LOG(fatal) << "Computed flat gas number reference per orbit is <=0"; + exit(1); + } else { + LOG(info) << "Set flat gas number to " << ref << " loopers per orbit using " << fitName << " from " << intRate << " Hz interaction rate."; + auto flat = true; + setFlatGas(flat, -1, ref); + } +} + +void GenTPCLoopers::SetAdjust(const float& adjust = 0.f) +{ + if (mFlatGas && mFlatGasOrbit && adjust >= -1.f && adjust != 0.f) { + LOG(info) << "Adjusting flat gas number per orbit by " << adjust * 100.f << "%"; + mFlatGasNumber = static_cast(std::round(mFlatGasNumber * (1.f + adjust))); + LOG(info) << "New flat gas number per orbit: " << mFlatGasNumber; + } +} + } // namespace eventgen } // namespace o2 \ No newline at end of file From a6f60e12edf933dbeb724b9ba7c51a4c5e49cffc Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Thu, 20 Nov 2025 22:40:33 +0100 Subject: [PATCH 037/234] Set automatic interaction rate from collision context --- .../include/Generators/TPCLoopersParam.h | 4 ++-- Generators/include/TPCLoopers.h | 3 +++ Generators/src/Generator.cxx | 10 +++++----- Generators/src/TPCLoopers.cxx | 19 +++++++++++++++++-- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/Generators/include/Generators/TPCLoopersParam.h b/Generators/include/Generators/TPCLoopersParam.h index 8571013cdec48..74c3cf4cff0ad 100644 --- a/Generators/include/Generators/TPCLoopersParam.h +++ b/Generators/include/Generators/TPCLoopersParam.h @@ -37,9 +37,9 @@ struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper mONNX_pair = nullptr; std::unique_ptr mONNX_compton = nullptr; @@ -122,6 +124,7 @@ class GenTPCLoopers double mTimeLimit = 0.0; // Time limit for the current event double mTimeEnd = 0.0; // Time limit for the last event float mLoopsFractionPairs = 0.08; // Fraction of loopers from Pairs + int mInteractionRate = 50000; // Interaction rate in Hz }; #endif // GENERATORS_WITH_TPCLOOPERS diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index fea1a38f1a146..18e28e4cc2668 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -107,7 +107,7 @@ bool Generator::initLoopersGen() } } const auto& nFlatGasLoopers = loopersParam.nFlatGasLoopers; - auto fraction_pairs = loopersParam.fraction_pairs; + const auto& fraction_pairs = loopersParam.fraction_pairs; std::array multiplier = {loopersParam.multiplier[0], loopersParam.multiplier[1]}; unsigned int nLoopersPairs = loopersParam.fixedNLoopers[0]; unsigned int nLoopersCompton = loopersParam.fixedNLoopers[1]; @@ -166,10 +166,6 @@ bool Generator::initLoopersGen() LOG(fatal) << "Error: collision system must be either 'PbPb' or 'pp'"; exit(1); } else { - if (intrate <= 0) { - LOG(fatal) << "Error: interaction rate must be positive!"; - exit(1); - } mLoopersGen->SetRate(nclxrate, (colsys == "PbPb") ? true : false, intrate); mLoopersGen->SetAdjust(loopersParam.adjust_flatgas); } @@ -217,6 +213,10 @@ Bool_t LOG(error) << "Failed to generate loopers event"; return kFALSE; } + if (mLoopersGen->getNLoopers() == 0) { + LOG(warning) << "No loopers generated for this event"; + return kTRUE; + } const auto& looperParticles = mLoopersGen->importParticles(); if (looperParticles.empty()) { LOG(error) << "Failed to import loopers particles"; diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx index b771b53ed33d2..0fb76fcd8c3a9 100644 --- a/Generators/src/TPCLoopers.cxx +++ b/Generators/src/TPCLoopers.cxx @@ -437,13 +437,28 @@ void GenTPCLoopers::SetRate(const std::string &rateFile, const bool &isPbPb = tr LOG(fatal) << "Error: Could not find fit function '" << fitName << "' in rate file!"; exit(1); } - auto ref = static_cast(std::floor(fit->Eval(intRate / 1000.))); // fit expects rate in kHz + mInteractionRate = intRate; + if (mInteractionRate < 0) { + mContextFile = std::filesystem::exists("collisioncontext.root") ? TFile::Open("collisioncontext.root") : nullptr; + if (!mContextFile || mContextFile->IsZombie()) { + LOG(fatal) << "Error: Interaction rate not provided and collision context file not found!"; + exit(1); + } + mCollisionContext = (o2::steer::DigitizationContext*)mContextFile->Get("DigitizationContext"); + mInteractionRate = std::floor(mCollisionContext->getDigitizerInteractionRate()); + LOG(info) << "Interaction rate retrieved from collision context: " << mInteractionRate << " Hz"; + if (mInteractionRate < 0) { + LOG(fatal) << "Error: Invalid interaction rate retrieved from collision context!"; + exit(1); + } + } + auto ref = static_cast(std::floor(fit->Eval(mInteractionRate / 1000.))); // fit expects rate in kHz rate_file.Close(); if (ref <= 0) { LOG(fatal) << "Computed flat gas number reference per orbit is <=0"; exit(1); } else { - LOG(info) << "Set flat gas number to " << ref << " loopers per orbit using " << fitName << " from " << intRate << " Hz interaction rate."; + LOG(info) << "Set flat gas number to " << ref << " loopers per orbit using " << fitName << " from " << mInteractionRate << " Hz interaction rate."; auto flat = true; setFlatGas(flat, -1, ref); } From b48d4ec35cdb9252783a46916898d4bfbac928f3 Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Mon, 24 Nov 2025 10:11:42 +0100 Subject: [PATCH 038/234] Fixed bug + cleaned code --- Generators/include/Generators/TPCLoopersParam.h | 4 ++-- Generators/src/Generator.cxx | 4 +--- Generators/src/TPCLoopers.cxx | 4 ---- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/Generators/include/Generators/TPCLoopersParam.h b/Generators/include/Generators/TPCLoopersParam.h index 74c3cf4cff0ad..24d905c59c967 100644 --- a/Generators/include/Generators/TPCLoopersParam.h +++ b/Generators/include/Generators/TPCLoopersParam.h @@ -39,8 +39,8 @@ struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper multiplier = {loopersParam.multiplier[0], loopersParam.multiplier[1]}; unsigned int nLoopersPairs = loopersParam.fixedNLoopers[0]; unsigned int nLoopersCompton = loopersParam.fixedNLoopers[1]; @@ -170,7 +168,7 @@ bool Generator::initLoopersGen() mLoopersGen->SetAdjust(loopersParam.adjust_flatgas); } } else { - // Otherwise, Poisson+Gauss sampling or fixed number of loopers will be used + // Otherwise, Poisson+Gauss sampling or fixed number of loopers per event will be used // Multiplier is applied only with distribution sampling // This configuration can be used for testing purposes, in all other cases flat gas is recommended mLoopersGen->SetNLoopers(nLoopersPairs, nLoopersCompton); diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx index 0fb76fcd8c3a9..07af5b25f99f9 100644 --- a/Generators/src/TPCLoopers.cxx +++ b/Generators/src/TPCLoopers.cxx @@ -27,10 +27,6 @@ void Scaler::load(const std::string &filename) normal_max = jsonArrayToVector(doc["normal"]["max"]); outlier_center = jsonArrayToVector(doc["outlier"]["center"]); outlier_scale = jsonArrayToVector(doc["outlier"]["scale"]); - std::vector normal_min; - std::vector normal_max; - std::vector outlier_center; - std::vector outlier_scale; } std::vector Scaler::inverse_transform(const std::vector &input) From e7a790b31d71d01e91a2a40123327febda65905f Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Mon, 24 Nov 2025 20:22:39 +0100 Subject: [PATCH 039/234] Improved logging + colsys check --- Generators/src/Generator.cxx | 31 ++++++++++++++++++++----------- Generators/src/TPCLoopers.cxx | 6 ++++-- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 9e083913c3bc7..9c16c0dfb7e92 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -50,11 +50,15 @@ Generator::Generator() : FairGenerator("ALICEo2", "ALICEo2 Generator"), if (transport) { bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); if (tpcActive) { - if(initLoopersGen()){ + if (initLoopersGen()) { mAddTPCLoopers = kTRUE; } + } else { + LOG(info) << "TPC not active in readout detectors: loopers fast generator disabled."; } } + } else { + LOG(info) << "Loopers fast generator turned OFF with veto flag."; } #endif } @@ -78,8 +82,12 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na if (initLoopersGen()) { mAddTPCLoopers = kTRUE; } + } else { + LOG(info) << "TPC not active in readout detectors: loopers fast generator disabled."; } } + } else { + LOG(info) << "Loopers fast generator turned OFF with veto flag."; } #endif } @@ -97,8 +105,14 @@ bool Generator::initLoopersGen() const auto& scaler_compton = gSystem->ExpandPathName(loopersParam.scaler_compton.c_str()); const auto& poisson = gSystem->ExpandPathName(loopersParam.poisson.c_str()); const auto& gauss = gSystem->ExpandPathName(loopersParam.gauss.c_str()); - auto flat_gas = loopersParam.flat_gas; + const auto& flat_gas = loopersParam.flat_gas; + const auto& colsys = loopersParam.colsys; if (flat_gas) { + if (colsys != "PbPb" && colsys != "pp") { + LOG(warning) << "Automatic background loopers configuration supports only 'pp' and 'PbPb' systems."; + LOG(warning) << "Fast loopers generator will remain OFF."; + return kFALSE; + } bool isContext = std::filesystem::exists("collisioncontext.root"); if (!isContext) { LOG(warning) << "Warning: No collisioncontext.root file found!"; @@ -156,17 +170,12 @@ bool Generator::initLoopersGen() try { // Create the TPC loopers generator with the provided parameters mLoopersGen = std::make_unique(model_pairs, model_compton, poisson, gauss, scaler_pair, scaler_compton); - auto& colsys = loopersParam.colsys; - auto &intrate = loopersParam.intrate; + const auto &intrate = loopersParam.intrate; // Configure the generator with flat gas loopers defined per orbit with clusters/track info + // If intrate is negative (default), automatic IR from collisioncontext.root will be used if (flat_gas) { - if (colsys != "PbPb" && colsys != "pp") { - LOG(fatal) << "Error: collision system must be either 'PbPb' or 'pp'"; - exit(1); - } else { - mLoopersGen->SetRate(nclxrate, (colsys == "PbPb") ? true : false, intrate); - mLoopersGen->SetAdjust(loopersParam.adjust_flatgas); - } + mLoopersGen->SetRate(nclxrate, (colsys == "PbPb") ? true : false, intrate); + mLoopersGen->SetAdjust(loopersParam.adjust_flatgas); } else { // Otherwise, Poisson+Gauss sampling or fixed number of loopers per event will be used // Multiplier is applied only with distribution sampling diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx index 07af5b25f99f9..ac1123b8d0bbd 100644 --- a/Generators/src/TPCLoopers.cxx +++ b/Generators/src/TPCLoopers.cxx @@ -141,7 +141,7 @@ GenTPCLoopers::GenTPCLoopers(std::string model_pairs, std::string model_compton, scaler_file[0].close(); scaler_file[1].close(); // Checking if the poisson file exists and it's not empty - if (poisson != "") + if (poisson != "" && poisson != "None" && poisson != "none") { std::ifstream poisson_file(poisson); if (!poisson_file.is_open() || poisson_file.peek() == std::ifstream::traits_type::eof()) @@ -157,7 +157,7 @@ GenTPCLoopers::GenTPCLoopers(std::string model_pairs, std::string model_compton, } } // Checking if the gauss file exists and it's not empty - if (gauss != "") + if (gauss != "" && gauss != "None" && gauss != "none") { std::ifstream gauss_file(gauss); if (!gauss_file.is_open() || gauss_file.peek() == std::ifstream::traits_type::eof()) @@ -205,9 +205,11 @@ Bool_t GenTPCLoopers::generateEvent() // Set number of loopers if poissonian params are available if (mPoissonSet) { mNLoopersPairs = static_cast(std::round(mMultiplier[0] * PoissonPairs())); + LOG(debug) << "Generated loopers pairs (Poisson): " << mNLoopersPairs; } if (mGaussSet) { mNLoopersCompton = static_cast(std::round(mMultiplier[1] * GaussianElectrons())); + LOG(debug) << "Generated compton electrons (Gauss): " << mNLoopersCompton; } // Generate pairs for (int i = 0; i < mNLoopersPairs; ++i) { From 569255b67223793d520de38f90463bc2f8ca6917 Mon Sep 17 00:00:00 2001 From: ALICE Action Bot Date: Tue, 25 Nov 2025 07:47:04 +0000 Subject: [PATCH 040/234] Please consider the following formatting changes --- Generators/include/Generators/Generator.h | 2 +- .../include/Generators/TPCLoopersParam.h | 24 +- Generators/include/TPCLoopers.h | 155 ++++++----- .../share/egconfig/ScalerComptonParams.json | 52 ++-- .../share/egconfig/ScalerPairParams.json | 64 ++--- Generators/src/Generator.cxx | 6 +- Generators/src/TPCLoopers.cxx | 256 ++++++++---------- 7 files changed, 271 insertions(+), 288 deletions(-) diff --git a/Generators/include/Generators/Generator.h b/Generators/include/Generators/Generator.h index 67277e20736ce..5a4921e036ca3 100644 --- a/Generators/include/Generators/Generator.h +++ b/Generators/include/Generators/Generator.h @@ -161,7 +161,7 @@ class Generator : public FairGenerator void updateSubGeneratorInformation(o2::dataformats::MCEventHeader* header) const; // loopers flag - Bool_t mAddTPCLoopers = kFALSE; // Flag is automatically set to true if TPC is in readout detectors, loopers are not vetoed and transport is enabled + Bool_t mAddTPCLoopers = kFALSE; // Flag is automatically set to true if TPC is in readout detectors, loopers are not vetoed and transport is enabled // collect an ID and a short description of sub-generator entities std::unordered_map mSubGeneratorsIdToDesc; // the current ID of the sub-generator used in the current event (if applicable) diff --git a/Generators/include/Generators/TPCLoopersParam.h b/Generators/include/Generators/TPCLoopersParam.h index 24d905c59c967..49c8e5f5927b6 100644 --- a/Generators/include/Generators/TPCLoopersParam.h +++ b/Generators/include/Generators/TPCLoopersParam.h @@ -28,22 +28,22 @@ namespace eventgen ** allow the user to modify them **/ struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper { - bool loopersVeto = false; // if true, no loopers are generated - std::string model_pairs = "ccdb://Users/m/mgiacalo/WGAN_ExtGenPair"; // ONNX model for e+e- pair production - std::string model_compton = "ccdb://Users/m/mgiacalo/WGAN_ExtGenCompton"; // ONNX model for Compton scattering - std::string poisson = "${O2_ROOT}/share/Generators/egconfig/poisson_params.csv"; // file with Poissonian parameters - std::string gauss = "${O2_ROOT}/share/Generators/egconfig/gaussian_params.csv"; // file with Gaussian parameters - std::string scaler_pair = "${O2_ROOT}/share/Generators/egconfig/ScalerPairParams.json"; // file with scaler parameters for e+e- pair production + bool loopersVeto = false; // if true, no loopers are generated + std::string model_pairs = "ccdb://Users/m/mgiacalo/WGAN_ExtGenPair"; // ONNX model for e+e- pair production + std::string model_compton = "ccdb://Users/m/mgiacalo/WGAN_ExtGenCompton"; // ONNX model for Compton scattering + std::string poisson = "${O2_ROOT}/share/Generators/egconfig/poisson_params.csv"; // file with Poissonian parameters + std::string gauss = "${O2_ROOT}/share/Generators/egconfig/gaussian_params.csv"; // file with Gaussian parameters + std::string scaler_pair = "${O2_ROOT}/share/Generators/egconfig/ScalerPairParams.json"; // file with scaler parameters for e+e- pair production std::string scaler_compton = "${O2_ROOT}/share/Generators/egconfig/ScalerComptonParams.json"; // file with scaler parameters for Compton scattering std::string nclxrate = "ccdb://Users/m/mgiacalo/ClustersTrackRatio"; // file with clusters/rate information per orbit std::string colsys = "PbPb"; // collision system (PbPb or pp) int intrate = -1; // Automatic IR from collision context if -1, else user-defined interaction rate in Hz - bool flat_gas = true; // if true, the gas density is considered flat in the TPC volume - unsigned int nFlatGasLoopers = 500; // number of loopers to be generated per event in case of flat gas [currently unused, kept for possible future debug developments] - float fraction_pairs = 0.08; // fraction of loopers [currently unused, kept for possible future debug developments] - float multiplier[2] = {1., 1.}; // multiplier for pairs and compton loopers for Poissonian and Gaussian sampling - unsigned int fixedNLoopers[2] = {1, 1}; // fixed number of loopers coming from pairs and compton electrons - valid if flat gas is false and both Poisson and Gaussian params files are empty - float adjust_flatgas = 0.f; // adjustment for the number of flat gas loopers per orbit (in percentage, e.g. -0.1 = -10%) [-1, inf)] + bool flat_gas = true; // if true, the gas density is considered flat in the TPC volume + unsigned int nFlatGasLoopers = 500; // number of loopers to be generated per event in case of flat gas [currently unused, kept for possible future debug developments] + float fraction_pairs = 0.08; // fraction of loopers [currently unused, kept for possible future debug developments] + float multiplier[2] = {1., 1.}; // multiplier for pairs and compton loopers for Poissonian and Gaussian sampling + unsigned int fixedNLoopers[2] = {1, 1}; // fixed number of loopers coming from pairs and compton electrons - valid if flat gas is false and both Poisson and Gaussian params files are empty + float adjust_flatgas = 0.f; // adjustment for the number of flat gas loopers per orbit (in percentage, e.g. -0.1 = -10%) [-1, inf)] O2ParamDef(GenTPCLoopersParam, "GenTPCLoopers"); }; diff --git a/Generators/include/TPCLoopers.h b/Generators/include/TPCLoopers.h index 8a4dc0030aa21..9addcf844e09d 100644 --- a/Generators/include/TPCLoopers.h +++ b/Generators/include/TPCLoopers.h @@ -26,33 +26,32 @@ extern Ort::Env global_env; // This class is responsible for loading the scaler parameters from a JSON file // and applying the inverse transformation to the generated data. -struct Scaler -{ - std::vector normal_min; - std::vector normal_max; - std::vector outlier_center; - std::vector outlier_scale; +struct Scaler { + std::vector normal_min; + std::vector normal_max; + std::vector outlier_center; + std::vector outlier_scale; - void load(const std::string &filename); + void load(const std::string& filename); - std::vector inverse_transform(const std::vector &input); + std::vector inverse_transform(const std::vector& input); -private: - std::vector jsonArrayToVector(const rapidjson::Value &jsonArray); + private: + std::vector jsonArrayToVector(const rapidjson::Value& jsonArray); }; // This class loads the ONNX model and generates samples using it. class ONNXGenerator { -public: - ONNXGenerator(Ort::Env &shared_env, const std::string &model_path); + public: + ONNXGenerator(Ort::Env& shared_env, const std::string& model_path); - std::vector generate_sample(); + std::vector generate_sample(); -private: - Ort::Env &env; - Ort::Session session; - TRandom3 rand_gen; + private: + Ort::Env& env; + Ort::Session session; + TRandom3 rand_gen; }; #endif // GENERATORS_WITH_TPCLOOPERS @@ -64,67 +63,67 @@ namespace eventgen #ifdef GENERATORS_WITH_TPCLOOPERS class GenTPCLoopers { - public: - GenTPCLoopers(std::string model_pairs = "tpcloopmodel.onnx", std::string model_compton = "tpcloopmodelcompton.onnx", - std::string poisson = "poisson.csv", std::string gauss = "gauss.csv", std::string scaler_pair = "scaler_pair.json", - std::string scaler_compton = "scaler_compton.json"); - - Bool_t generateEvent(); - - Bool_t generateEvent(double &time_limit); - - std::vector importParticles(); - - unsigned int PoissonPairs(); - - unsigned int GaussianElectrons(); - - void SetNLoopers(unsigned int &nsig_pair, unsigned int &nsig_compton); - - void SetMultiplier(std::array &mult); - - void setFlatGas(Bool_t& flat, const Int_t& number, const Int_t& nloopers_orbit); - - void setFractionPairs(float &fractionPairs); - - void SetRate(const std::string &rateFile, const bool &isPbPb, const int &intRate); - - void SetAdjust(const float &adjust); - - unsigned int getNLoopers() const { return (mNLoopersPairs + mNLoopersCompton); } - - private: - std::unique_ptr mONNX_pair = nullptr; - std::unique_ptr mONNX_compton = nullptr; - std::unique_ptr mScaler_pair = nullptr; - std::unique_ptr mScaler_compton = nullptr; - double mPoisson[3] = {0.0, 0.0, 0.0}; // Mu, Min and Max of Poissonian - double mGauss[4] = {0.0, 0.0, 0.0, 0.0}; // Mean, Std, Min, Max - std::vector> mGenPairs; - std::vector> mGenElectrons; - unsigned int mNLoopersPairs = -1; - unsigned int mNLoopersCompton = -1; - std::array mMultiplier = {1., 1.}; - bool mPoissonSet = false; - bool mGaussSet = false; - // Random number generator - TRandom3 mRandGen; - // Masses of the electrons and positrons - TDatabasePDG *mPDG = TDatabasePDG::Instance(); - double mMass_e = mPDG->GetParticle(11)->Mass(); - double mMass_p = mPDG->GetParticle(-11)->Mass(); - int mCurrentEvent = 0; // Current event number, used for adaptive loopers - TFile *mContextFile = nullptr; // Input collision context file - o2::steer::DigitizationContext *mCollisionContext = nullptr; // Pointer to the digitization context - std::vector mInteractionTimeRecords; // Interaction time records from collision context - Bool_t mFlatGas = false; // Flag to indicate if flat gas loopers are used - Bool_t mFlatGasOrbit = false; // Flag to indicate if flat gas loopers are per orbit - Int_t mFlatGasNumber = -1; // Number of flat gas loopers per event - double mIntTimeRecMean = 1.0; // Average interaction time record used for the reference - double mTimeLimit = 0.0; // Time limit for the current event - double mTimeEnd = 0.0; // Time limit for the last event - float mLoopsFractionPairs = 0.08; // Fraction of loopers from Pairs - int mInteractionRate = 50000; // Interaction rate in Hz + public: + GenTPCLoopers(std::string model_pairs = "tpcloopmodel.onnx", std::string model_compton = "tpcloopmodelcompton.onnx", + std::string poisson = "poisson.csv", std::string gauss = "gauss.csv", std::string scaler_pair = "scaler_pair.json", + std::string scaler_compton = "scaler_compton.json"); + + Bool_t generateEvent(); + + Bool_t generateEvent(double& time_limit); + + std::vector importParticles(); + + unsigned int PoissonPairs(); + + unsigned int GaussianElectrons(); + + void SetNLoopers(unsigned int& nsig_pair, unsigned int& nsig_compton); + + void SetMultiplier(std::array& mult); + + void setFlatGas(Bool_t& flat, const Int_t& number, const Int_t& nloopers_orbit); + + void setFractionPairs(float& fractionPairs); + + void SetRate(const std::string& rateFile, const bool& isPbPb, const int& intRate); + + void SetAdjust(const float& adjust); + + unsigned int getNLoopers() const { return (mNLoopersPairs + mNLoopersCompton); } + + private: + std::unique_ptr mONNX_pair = nullptr; + std::unique_ptr mONNX_compton = nullptr; + std::unique_ptr mScaler_pair = nullptr; + std::unique_ptr mScaler_compton = nullptr; + double mPoisson[3] = {0.0, 0.0, 0.0}; // Mu, Min and Max of Poissonian + double mGauss[4] = {0.0, 0.0, 0.0, 0.0}; // Mean, Std, Min, Max + std::vector> mGenPairs; + std::vector> mGenElectrons; + unsigned int mNLoopersPairs = -1; + unsigned int mNLoopersCompton = -1; + std::array mMultiplier = {1., 1.}; + bool mPoissonSet = false; + bool mGaussSet = false; + // Random number generator + TRandom3 mRandGen; + // Masses of the electrons and positrons + TDatabasePDG* mPDG = TDatabasePDG::Instance(); + double mMass_e = mPDG->GetParticle(11)->Mass(); + double mMass_p = mPDG->GetParticle(-11)->Mass(); + int mCurrentEvent = 0; // Current event number, used for adaptive loopers + TFile* mContextFile = nullptr; // Input collision context file + o2::steer::DigitizationContext* mCollisionContext = nullptr; // Pointer to the digitization context + std::vector mInteractionTimeRecords; // Interaction time records from collision context + Bool_t mFlatGas = false; // Flag to indicate if flat gas loopers are used + Bool_t mFlatGasOrbit = false; // Flag to indicate if flat gas loopers are per orbit + Int_t mFlatGasNumber = -1; // Number of flat gas loopers per event + double mIntTimeRecMean = 1.0; // Average interaction time record used for the reference + double mTimeLimit = 0.0; // Time limit for the current event + double mTimeEnd = 0.0; // Time limit for the last event + float mLoopsFractionPairs = 0.08; // Fraction of loopers from Pairs + int mInteractionRate = 50000; // Interaction rate in Hz }; #endif // GENERATORS_WITH_TPCLOOPERS diff --git a/Generators/share/egconfig/ScalerComptonParams.json b/Generators/share/egconfig/ScalerComptonParams.json index d8e654847f46e..157647fee2db7 100644 --- a/Generators/share/egconfig/ScalerComptonParams.json +++ b/Generators/share/egconfig/ScalerComptonParams.json @@ -1,28 +1,28 @@ { - "normal": { - "min": [ - -0.0108811147511005, - -0.0098758740350604, - -0.0103233363479375, - -260.0542297363281, - -259.80059814453125 - ], - "max": [ - 0.0108060473576188, - 0.0103057539090514, - 0.0106524610891938, - 260.0343933105469, - 259.62890625 - ] - }, - "outlier": { - "center": [ - -71.39387130737305, - 96791.23828125 - ], - "scale": [ - 265.9389114379883, - 230762.30981445312 - ] - } + "normal": { + "min": [ + -0.0108811147511005, + -0.0098758740350604, + -0.0103233363479375, + -260.0542297363281, + -259.80059814453125 + ], + "max": [ + 0.0108060473576188, + 0.0103057539090514, + 0.0106524610891938, + 260.0343933105469, + 259.62890625 + ] + }, + "outlier": { + "center": [ + -71.39387130737305, + 96791.23828125 + ], + "scale": [ + 265.9389114379883, + 230762.30981445312 + ] + } } \ No newline at end of file diff --git a/Generators/share/egconfig/ScalerPairParams.json b/Generators/share/egconfig/ScalerPairParams.json index 61434bfa2462e..57cdac421d3f6 100644 --- a/Generators/share/egconfig/ScalerPairParams.json +++ b/Generators/share/egconfig/ScalerPairParams.json @@ -1,34 +1,34 @@ { - "normal": { - "min": [ - -0.0073022879660129, - -0.0077305701561272, - -0.0076750442385673, - -0.0082916170358657, - -0.0079681202769279, - -0.0077468422241508, - -255.6164093017578, - -252.9441680908203 - ], - "max": [ - 0.007688719779253, - 0.0077241472899913, - 0.0075828479602932, - 0.00813714787364, - 0.0083825681358575, - 0.0073839174583554, - 256.2904968261719, - 253.4925842285156 - ] - }, - "outlier": { - "center": [ - -79.66580963134766, - 141535.640625 - ], - "scale": [ - 250.8921127319336, - 222363.16015625 - ] - } + "normal": { + "min": [ + -0.0073022879660129, + -0.0077305701561272, + -0.0076750442385673, + -0.0082916170358657, + -0.0079681202769279, + -0.0077468422241508, + -255.6164093017578, + -252.9441680908203 + ], + "max": [ + 0.007688719779253, + 0.0077241472899913, + 0.0075828479602932, + 0.00813714787364, + 0.0083825681358575, + 0.0073839174583554, + 256.2904968261719, + 253.4925842285156 + ] + }, + "outlier": { + "center": [ + -79.66580963134766, + 141535.640625 + ], + "scale": [ + 250.8921127319336, + 222363.16015625 + ] + } } \ No newline at end of file diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 9c16c0dfb7e92..ce49254799587 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -170,7 +170,7 @@ bool Generator::initLoopersGen() try { // Create the TPC loopers generator with the provided parameters mLoopersGen = std::make_unique(model_pairs, model_compton, poisson, gauss, scaler_pair, scaler_compton); - const auto &intrate = loopersParam.intrate; + const auto& intrate = loopersParam.intrate; // Configure the generator with flat gas loopers defined per orbit with clusters/track info // If intrate is negative (default), automatic IR from collisioncontext.root will be used if (flat_gas) { @@ -209,7 +209,7 @@ Bool_t Generator::finalizeEvent() { #ifdef GENERATORS_WITH_TPCLOOPERS - if(mAddTPCLoopers) { + if (mAddTPCLoopers) { if (!mLoopersGen) { LOG(error) << "Loopers generator not initialized"; return kFALSE; @@ -268,7 +268,7 @@ Bool_t } /** Event finalization**/ - if(!finalizeEvent()) { + if (!finalizeEvent()) { LOG(error) << "ReadEvent failed in finalizeEvent"; return kFALSE; } diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx index ac1123b8d0bbd..258b6cce07b5b 100644 --- a/Generators/src/TPCLoopers.cxx +++ b/Generators/src/TPCLoopers.cxx @@ -6,7 +6,7 @@ Ort::Env global_env(ORT_LOGGING_LEVEL_WARNING, "GlobalEnv"); // This class is responsible for loading the scaler parameters from a JSON file // and applying the inverse transformation to the generated data. -void Scaler::load(const std::string &filename) +void Scaler::load(const std::string& filename) { std::ifstream file(filename); if (!file.is_open()) { @@ -27,76 +27,73 @@ void Scaler::load(const std::string &filename) normal_max = jsonArrayToVector(doc["normal"]["max"]); outlier_center = jsonArrayToVector(doc["outlier"]["center"]); outlier_scale = jsonArrayToVector(doc["outlier"]["scale"]); -} +} -std::vector Scaler::inverse_transform(const std::vector &input) +std::vector Scaler::inverse_transform(const std::vector& input) { - std::vector output; - for (int i = 0; i < input.size(); ++i) - { - if (i < input.size() - 2) - output.push_back(input[i] * (normal_max[i] - normal_min[i]) + normal_min[i]); - else - output.push_back(input[i] * outlier_scale[i - (input.size() - 2)] + outlier_center[i - (input.size() - 2)]); - } + std::vector output; + for (int i = 0; i < input.size(); ++i) { + if (i < input.size() - 2) + output.push_back(input[i] * (normal_max[i] - normal_min[i]) + normal_min[i]); + else + output.push_back(input[i] * outlier_scale[i - (input.size() - 2)] + outlier_center[i - (input.size() - 2)]); + } - return output; + return output; } -std::vector Scaler::jsonArrayToVector(const rapidjson::Value &jsonArray) +std::vector Scaler::jsonArrayToVector(const rapidjson::Value& jsonArray) { - std::vector vec; - for (int i = 0; i < jsonArray.Size(); ++i) - { - vec.push_back(jsonArray[i].GetDouble()); - } - return vec; + std::vector vec; + for (int i = 0; i < jsonArray.Size(); ++i) { + vec.push_back(jsonArray[i].GetDouble()); + } + return vec; } // This class loads the ONNX model and generates samples using it. ONNXGenerator::ONNXGenerator(Ort::Env& shared_env, const std::string& model_path) -: env(shared_env), session(env, model_path.c_str(), Ort::SessionOptions{}) + : env(shared_env), session(env, model_path.c_str(), Ort::SessionOptions{}) { - // Create session options - Ort::SessionOptions session_options; - session = Ort::Session(env, model_path.c_str(), session_options); + // Create session options + Ort::SessionOptions session_options; + session = Ort::Session(env, model_path.c_str(), session_options); } std::vector ONNXGenerator::generate_sample() { - Ort::AllocatorWithDefaultOptions allocator; - - // Generate a latent vector (z) - std::vector z(100); - for (auto &v : z) - v = rand_gen.Gaus(0.0, 1.0); - - // Prepare input tensor - std::vector input_shape = {1, 100}; - // Get memory information - Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); - - // Create input tensor correctly - Ort::Value input_tensor = Ort::Value::CreateTensor( - memory_info, z.data(), z.size(), input_shape.data(), input_shape.size()); - // Run inference - const char *input_names[] = {"z"}; - const char *output_names[] = {"output"}; - auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_names, &input_tensor, 1, output_names, 1); - - // Extract output - float *output_data = output_tensors.front().GetTensorMutableData(); - // Get the size of the output tensor - auto output_tensor_info = output_tensors.front().GetTensorTypeAndShapeInfo(); - size_t output_data_size = output_tensor_info.GetElementCount(); // Total number of elements in the tensor - std::vector output; - for (int i = 0; i < output_data_size; ++i) - { - output.push_back(output_data[i]); - } + Ort::AllocatorWithDefaultOptions allocator; + + // Generate a latent vector (z) + std::vector z(100); + for (auto& v : z) + v = rand_gen.Gaus(0.0, 1.0); + + // Prepare input tensor + std::vector input_shape = {1, 100}; + // Get memory information + Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); + + // Create input tensor correctly + Ort::Value input_tensor = Ort::Value::CreateTensor( + memory_info, z.data(), z.size(), input_shape.data(), input_shape.size()); + // Run inference + const char* input_names[] = {"z"}; + const char* output_names[] = {"output"}; + auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_names, &input_tensor, 1, output_names, 1); + + // Extract output + float* output_data = output_tensors.front().GetTensorMutableData(); + // Get the size of the output tensor + auto output_tensor_info = output_tensors.front().GetTensorTypeAndShapeInfo(); + size_t output_data_size = output_tensor_info.GetElementCount(); // Total number of elements in the tensor + std::vector output; + for (int i = 0; i < output_data_size; ++i) { + output.push_back(output_data[i]); + } - return output; + return output; } namespace o2 @@ -105,79 +102,67 @@ namespace eventgen { GenTPCLoopers::GenTPCLoopers(std::string model_pairs, std::string model_compton, - std::string poisson, std::string gauss, std::string scaler_pair, - std::string scaler_compton) + std::string poisson, std::string gauss, std::string scaler_pair, + std::string scaler_compton) { - // Checking if the model files exist and are not empty - std::ifstream model_file[2]; - model_file[0].open(model_pairs); - model_file[1].open(model_compton); - if (!model_file[0].is_open() || model_file[0].peek() == std::ifstream::traits_type::eof()) - { - LOG(fatal) << "Error: Pairs model file is empty or does not exist!"; - exit(1); - } - if (!model_file[1].is_open() || model_file[1].peek() == std::ifstream::traits_type::eof()) - { - LOG(fatal) << "Error: Compton model file is empty or does not exist!"; - exit(1); - } - model_file[0].close(); - model_file[1].close(); - // Checking if the scaler files exist and are not empty - std::ifstream scaler_file[2]; - scaler_file[0].open(scaler_pair); - scaler_file[1].open(scaler_compton); - if (!scaler_file[0].is_open() || scaler_file[0].peek() == std::ifstream::traits_type::eof()) - { - LOG(fatal) << "Error: Pairs scaler file is empty or does not exist!"; - exit(1); - } - if (!scaler_file[1].is_open() || scaler_file[1].peek() == std::ifstream::traits_type::eof()) - { - LOG(fatal) << "Error: Compton scaler file is empty or does not exist!"; - exit(1); - } - scaler_file[0].close(); - scaler_file[1].close(); - // Checking if the poisson file exists and it's not empty - if (poisson != "" && poisson != "None" && poisson != "none") - { - std::ifstream poisson_file(poisson); - if (!poisson_file.is_open() || poisson_file.peek() == std::ifstream::traits_type::eof()) - { - LOG(fatal) << "Error: Poisson file is empty or does not exist!"; - exit(1); - } - else - { - poisson_file >> mPoisson[0] >> mPoisson[1] >> mPoisson[2]; - poisson_file.close(); - mPoissonSet = true; - } + // Checking if the model files exist and are not empty + std::ifstream model_file[2]; + model_file[0].open(model_pairs); + model_file[1].open(model_compton); + if (!model_file[0].is_open() || model_file[0].peek() == std::ifstream::traits_type::eof()) { + LOG(fatal) << "Error: Pairs model file is empty or does not exist!"; + exit(1); + } + if (!model_file[1].is_open() || model_file[1].peek() == std::ifstream::traits_type::eof()) { + LOG(fatal) << "Error: Compton model file is empty or does not exist!"; + exit(1); + } + model_file[0].close(); + model_file[1].close(); + // Checking if the scaler files exist and are not empty + std::ifstream scaler_file[2]; + scaler_file[0].open(scaler_pair); + scaler_file[1].open(scaler_compton); + if (!scaler_file[0].is_open() || scaler_file[0].peek() == std::ifstream::traits_type::eof()) { + LOG(fatal) << "Error: Pairs scaler file is empty or does not exist!"; + exit(1); + } + if (!scaler_file[1].is_open() || scaler_file[1].peek() == std::ifstream::traits_type::eof()) { + LOG(fatal) << "Error: Compton scaler file is empty or does not exist!"; + exit(1); + } + scaler_file[0].close(); + scaler_file[1].close(); + // Checking if the poisson file exists and it's not empty + if (poisson != "" && poisson != "None" && poisson != "none") { + std::ifstream poisson_file(poisson); + if (!poisson_file.is_open() || poisson_file.peek() == std::ifstream::traits_type::eof()) { + LOG(fatal) << "Error: Poisson file is empty or does not exist!"; + exit(1); + } else { + poisson_file >> mPoisson[0] >> mPoisson[1] >> mPoisson[2]; + poisson_file.close(); + mPoissonSet = true; } - // Checking if the gauss file exists and it's not empty - if (gauss != "" && gauss != "None" && gauss != "none") - { - std::ifstream gauss_file(gauss); - if (!gauss_file.is_open() || gauss_file.peek() == std::ifstream::traits_type::eof()) - { - LOG(fatal) << "Error: Gauss file is empty or does not exist!"; - exit(1); - } - else - { - gauss_file >> mGauss[0] >> mGauss[1] >> mGauss[2] >> mGauss[3]; - gauss_file.close(); - mGaussSet = true; - } + } + // Checking if the gauss file exists and it's not empty + if (gauss != "" && gauss != "None" && gauss != "none") { + std::ifstream gauss_file(gauss); + if (!gauss_file.is_open() || gauss_file.peek() == std::ifstream::traits_type::eof()) { + LOG(fatal) << "Error: Gauss file is empty or does not exist!"; + exit(1); + } else { + gauss_file >> mGauss[0] >> mGauss[1] >> mGauss[2] >> mGauss[3]; + gauss_file.close(); + mGaussSet = true; } - mONNX_pair = std::make_unique(global_env, model_pairs); - mScaler_pair = std::make_unique(); - mScaler_pair->load(scaler_pair); - mONNX_compton = std::make_unique(global_env, model_compton); - mScaler_compton = std::make_unique(); - mScaler_compton->load(scaler_compton); + } + mONNX_pair = std::make_unique(global_env, model_pairs); + mScaler_pair = std::make_unique(); + mScaler_pair->load(scaler_pair); + mONNX_compton = std::make_unique(global_env, model_compton); + mScaler_compton = std::make_unique(); + mScaler_compton->load(scaler_compton); } Bool_t GenTPCLoopers::generateEvent() @@ -352,17 +337,16 @@ void GenTPCLoopers::SetNLoopers(unsigned int& nsig_pair, unsigned int& nsig_comp void GenTPCLoopers::SetMultiplier(std::array& mult) { - // Multipliers will work only if the poissonian and gaussian parameters are set - // otherwise they will be ignored - if (mult[0] < 0 || mult[1] < 0) - { - LOG(fatal) << "Error: Multiplier values must be non-negative!"; - exit(1); - } else { - LOG(info) << "Multiplier values set to: Pair = " << mult[0] << ", Compton = " << mult[1]; - mMultiplier[0] = mult[0]; - mMultiplier[1] = mult[1]; - } + // Multipliers will work only if the poissonian and gaussian parameters are set + // otherwise they will be ignored + if (mult[0] < 0 || mult[1] < 0) { + LOG(fatal) << "Error: Multiplier values must be non-negative!"; + exit(1); + } else { + LOG(info) << "Multiplier values set to: Pair = " << mult[0] << ", Compton = " << mult[1]; + mMultiplier[0] = mult[0]; + mMultiplier[1] = mult[1]; + } } void GenTPCLoopers::setFlatGas(Bool_t& flat, const Int_t& number = -1, const Int_t& nloopers_orbit = -1) @@ -421,7 +405,7 @@ void GenTPCLoopers::setFractionPairs(float& fractionPairs) LOG(info) << "Pairs fraction set to: " << mLoopsFractionPairs; } -void GenTPCLoopers::SetRate(const std::string &rateFile, const bool &isPbPb = true, const int &intRate = 50000) +void GenTPCLoopers::SetRate(const std::string& rateFile, const bool& isPbPb = true, const int& intRate = 50000) { // Checking if the rate file exists and is not empty TFile rate_file(rateFile.c_str(), "READ"); From 6837bccb95a137dd24d42d44fd4db5579ad3dbf9 Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Tue, 25 Nov 2025 08:54:19 +0100 Subject: [PATCH 041/234] Add copyright headers --- Generators/include/TPCLoopers.h | 13 +++++++++++++ Generators/src/TPCLoopers.cxx | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/Generators/include/TPCLoopers.h b/Generators/include/TPCLoopers.h index 9addcf844e09d..57d178667b497 100644 --- a/Generators/include/TPCLoopers.h +++ b/Generators/include/TPCLoopers.h @@ -1,3 +1,16 @@ +// Copyright 2024-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author M+Giacalone - September 2025 + #ifndef ALICEO2_EVENTGEN_TPCLOOPERS_H_ #define ALICEO2_EVENTGEN_TPCLOOPERS_H_ diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx index 258b6cce07b5b..8dff795de40a3 100644 --- a/Generators/src/TPCLoopers.cxx +++ b/Generators/src/TPCLoopers.cxx @@ -1,3 +1,16 @@ +// Copyright 2024-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author M+Giacalone - September 2025 + #include "Generators/TPCLoopers.h" // Static Ort::Env instance for multiple onnx model loading From 1989aed2c6064aaec4d11dfaba2a08d101fed386 Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Tue, 25 Nov 2025 12:55:13 +0100 Subject: [PATCH 042/234] Corrected include folder --- Generators/CMakeLists.txt | 19 ++--- Generators/include/Generators/Generator.h | 5 +- .../include/{ => Generators}/TPCLoopers.h | 44 ++++++----- .../include/Generators/TPCLoopersParam.h | 35 ++++---- Generators/share/TPCLoopers/README.md | 79 +++++++++++++++++++ .../ScalerComptonParams.json | 0 .../ScalerPairParams.json | 0 .../gaussian_params.csv | 0 .../poisson_params.csv | 0 Generators/src/Generator.cxx | 28 ++++--- Generators/src/TPCLoopers.cxx | 40 +++++++--- 11 files changed, 172 insertions(+), 78 deletions(-) rename Generators/include/{ => Generators}/TPCLoopers.h (71%) create mode 100644 Generators/share/TPCLoopers/README.md rename Generators/share/{egconfig => TPCLoopers}/ScalerComptonParams.json (100%) rename Generators/share/{egconfig => TPCLoopers}/ScalerPairParams.json (100%) rename Generators/share/{egconfig => TPCLoopers}/gaussian_params.csv (100%) rename Generators/share/{egconfig => TPCLoopers}/poisson_params.csv (100%) diff --git a/Generators/CMakeLists.txt b/Generators/CMakeLists.txt index f1921b8d8d72a..287536ff118f7 100644 --- a/Generators/CMakeLists.txt +++ b/Generators/CMakeLists.txt @@ -41,8 +41,8 @@ o2_add_library(Generators src/GeneratorTParticleParam.cxx src/GeneratorService.cxx src/FlowMapper.cxx - $<$:src/TPCLoopers.cxx> - $<$:src/TPCLoopersParam.cxx> + src/TPCLoopers.cxx + src/TPCLoopersParam.cxx $<$:src/GeneratorPythia8.cxx> $<$:src/DecayerPythia8.cxx> $<$:src/GeneratorPythia8Param.cxx> @@ -55,7 +55,7 @@ o2_add_library(Generators PUBLIC_LINK_LIBRARIES FairRoot::Base O2::SimConfig O2::CommonUtils O2::DetectorsBase O2::ZDCBase O2::SimulationDataFormat ${pythiaTarget} ${hepmcTarget} FairRoot::Gen - $<$:onnxruntime::onnxruntime> + onnxruntime::onnxruntime TARGETVARNAME targetName) if(pythia_FOUND) @@ -66,9 +66,7 @@ if(HepMC3_FOUND) target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_HEPMC3) endif() -if(onnxruntime_FOUND) - target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_TPCLOOPERS) -endif() +target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_TPCLOOPERS) set(headers include/Generators/Generator.h @@ -95,11 +93,9 @@ set(headers include/Generators/FlowMapper.h ) -if(onnxruntime_FOUND) - list(APPEND headers - include/Generators/TPCLoopers.h - include/Generators/TPCLoopersParam.h) -endif() +list(APPEND headers + include/Generators/TPCLoopers.h + include/Generators/TPCLoopersParam.h) if(pythia_FOUND) list(APPEND headers @@ -171,4 +167,5 @@ endif() o2_data_file(COPY share/external DESTINATION Generators) o2_data_file(COPY share/egconfig DESTINATION Generators) +o2_data_file(COPY share/TPCLoopers DESTINATION Generators) o2_data_file(COPY share/pythia8 DESTINATION Generators) diff --git a/Generators/include/Generators/Generator.h b/Generators/include/Generators/Generator.h index 5a4921e036ca3..3484601aa42bb 100644 --- a/Generators/include/Generators/Generator.h +++ b/Generators/include/Generators/Generator.h @@ -17,7 +17,6 @@ #include "FairGenerator.h" #include "TParticle.h" #include "Generators/Trigger.h" -#include "CCDB/BasicCCDBManager.h" #ifdef GENERATORS_WITH_TPCLOOPERS #include "Generators/TPCLoopers.h" #include "Generators/TPCLoopersParam.h" @@ -172,8 +171,8 @@ class Generator : public FairGenerator #ifdef GENERATORS_WITH_TPCLOOPERS // Loopers generator instance - std::unique_ptr mLoopersGen = nullptr; - bool initLoopersGen(); + std::unique_ptr mTPCLoopersGen = nullptr; + bool initTPCLoopersGen(); #endif ClassDefOverride(Generator, 2); diff --git a/Generators/include/TPCLoopers.h b/Generators/include/Generators/TPCLoopers.h similarity index 71% rename from Generators/include/TPCLoopers.h rename to Generators/include/Generators/TPCLoopers.h index 57d178667b497..6a1d3ef262e22 100644 --- a/Generators/include/TPCLoopers.h +++ b/Generators/include/Generators/TPCLoopers.h @@ -17,21 +17,11 @@ #ifdef GENERATORS_WITH_TPCLOOPERS #include #endif -#include #include -#include #include -#include "CCDB/CCDBTimeStampUtils.h" -#include "CCDB/CcdbApi.h" -#include "DetectorsRaw/HBFUtils.h" #include "TRandom3.h" -#include "TDatabasePDG.h" #include -#include -#include "SimulationDataFormat/MCGenProperties.h" #include "TParticle.h" -#include "TF1.h" -#include #ifdef GENERATORS_WITH_TPCLOOPERS // Static Ort::Env instance for multiple onnx model loading @@ -39,6 +29,8 @@ extern Ort::Env global_env; // This class is responsible for loading the scaler parameters from a JSON file // and applying the inverse transformation to the generated data. +// Inferenced output is scaled (min-max normalization or robust scaling for outlier features) during training, +// so we need to revert this transformation to get physical values. struct Scaler { std::vector normal_min; std::vector normal_max; @@ -74,6 +66,20 @@ namespace eventgen { #ifdef GENERATORS_WITH_TPCLOOPERS +/** + * Generator for TPC Loopers based on pre-trained ONNX models. + * Currently it generates loopers as electron-positron pairs and Compton electrons + * according to specified distributions and parameters. + * This can be extended to other types of background processes in the future (e.g. slow neutron spallation products, saturation tail). + * Multiple configuration options are available: + * - Flat gas: loopers are generated uniformly per event taking a reference value which can be either the LHC orbit time or the average interaction time record interval from the collision context. + * ==> Current automatic setup (default) sets the interaction rate automatically from the collision context and the reference value per orbit is calculated from an external file. + * ==> Number of loopers per orbit can be adjusted via a specific parameter. + * - Poisson + Gaussian sampling: number of loopers are sampled from Poissonian (for pairs) and Gaussian (for Compton electrons) distributions based on provided parameters. + * ==> flat gas must be disabled to use this option. + * - Fixed number of loopers per event + * ==> flat gas must be disabled to use this option and Poissonian/Gaussian parameters file should be set to None + */ class GenTPCLoopers { public: @@ -83,7 +89,7 @@ class GenTPCLoopers Bool_t generateEvent(); - Bool_t generateEvent(double& time_limit); + Bool_t generateEvent(double time_limit); std::vector importParticles(); @@ -91,17 +97,17 @@ class GenTPCLoopers unsigned int GaussianElectrons(); - void SetNLoopers(unsigned int& nsig_pair, unsigned int& nsig_compton); + void SetNLoopers(unsigned int nsig_pair, unsigned int nsig_compton); - void SetMultiplier(std::array& mult); + void SetMultiplier(const std::array& mult); - void setFlatGas(Bool_t& flat, const Int_t& number, const Int_t& nloopers_orbit); + void setFlatGas(Bool_t flat, Int_t number = -1, Int_t nloopers_orbit = -1); - void setFractionPairs(float& fractionPairs); + void setFractionPairs(float fractionPairs); - void SetRate(const std::string& rateFile, const bool& isPbPb, const int& intRate); + void SetRate(const std::string& rateFile, bool isPbPb, int intRate = 50000); - void SetAdjust(const float& adjust); + void SetAdjust(float adjust = 0.f); unsigned int getNLoopers() const { return (mNLoopersPairs + mNLoopersCompton); } @@ -121,10 +127,6 @@ class GenTPCLoopers bool mGaussSet = false; // Random number generator TRandom3 mRandGen; - // Masses of the electrons and positrons - TDatabasePDG* mPDG = TDatabasePDG::Instance(); - double mMass_e = mPDG->GetParticle(11)->Mass(); - double mMass_p = mPDG->GetParticle(-11)->Mass(); int mCurrentEvent = 0; // Current event number, used for adaptive loopers TFile* mContextFile = nullptr; // Input collision context file o2::steer::DigitizationContext* mCollisionContext = nullptr; // Pointer to the digitization context diff --git a/Generators/include/Generators/TPCLoopersParam.h b/Generators/include/Generators/TPCLoopersParam.h index 49c8e5f5927b6..87e4510d6e617 100644 --- a/Generators/include/Generators/TPCLoopersParam.h +++ b/Generators/include/Generators/TPCLoopersParam.h @@ -24,26 +24,27 @@ namespace eventgen /** ** a parameter class/struct to keep the settings of - ** the tpc loopers event-generator and + ** the TPC loopers event-generator and ** allow the user to modify them **/ struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper { - bool loopersVeto = false; // if true, no loopers are generated - std::string model_pairs = "ccdb://Users/m/mgiacalo/WGAN_ExtGenPair"; // ONNX model for e+e- pair production - std::string model_compton = "ccdb://Users/m/mgiacalo/WGAN_ExtGenCompton"; // ONNX model for Compton scattering - std::string poisson = "${O2_ROOT}/share/Generators/egconfig/poisson_params.csv"; // file with Poissonian parameters - std::string gauss = "${O2_ROOT}/share/Generators/egconfig/gaussian_params.csv"; // file with Gaussian parameters - std::string scaler_pair = "${O2_ROOT}/share/Generators/egconfig/ScalerPairParams.json"; // file with scaler parameters for e+e- pair production - std::string scaler_compton = "${O2_ROOT}/share/Generators/egconfig/ScalerComptonParams.json"; // file with scaler parameters for Compton scattering - std::string nclxrate = "ccdb://Users/m/mgiacalo/ClustersTrackRatio"; // file with clusters/rate information per orbit - std::string colsys = "PbPb"; // collision system (PbPb or pp) - int intrate = -1; // Automatic IR from collision context if -1, else user-defined interaction rate in Hz - bool flat_gas = true; // if true, the gas density is considered flat in the TPC volume - unsigned int nFlatGasLoopers = 500; // number of loopers to be generated per event in case of flat gas [currently unused, kept for possible future debug developments] - float fraction_pairs = 0.08; // fraction of loopers [currently unused, kept for possible future debug developments] - float multiplier[2] = {1., 1.}; // multiplier for pairs and compton loopers for Poissonian and Gaussian sampling - unsigned int fixedNLoopers[2] = {1, 1}; // fixed number of loopers coming from pairs and compton electrons - valid if flat gas is false and both Poisson and Gaussian params files are empty - float adjust_flatgas = 0.f; // adjustment for the number of flat gas loopers per orbit (in percentage, e.g. -0.1 = -10%) [-1, inf)] + bool loopersVeto = false; // if true, no loopers are generated + // Current files are set to custom user CCDB paths, TO BE CHANGED + std::string model_pairs = "ccdb://Users/m/mgiacalo/WGAN_ExtGenPair"; // ONNX model for e+e- pair production + std::string model_compton = "ccdb://Users/m/mgiacalo/WGAN_ExtGenCompton"; // ONNX model for Compton scattering + std::string poisson = "${O2_ROOT}/share/Generators/TPCLoopers/poisson_params.csv"; // file with Poissonian parameters + std::string gauss = "${O2_ROOT}/share/Generators/TPCLoopers/gaussian_params.csv"; // file with Gaussian parameters + std::string scaler_pair = "${O2_ROOT}/share/Generators/TPCLoopers/ScalerPairParams.json"; // file with scaler parameters for e+e- pair production + std::string scaler_compton = "${O2_ROOT}/share/Generators/TPCLoopers/ScalerComptonParams.json"; // file with scaler parameters for Compton scattering + std::string nclxrate = "ccdb://Users/m/mgiacalo/ClustersTrackRatio"; // file with clusters/rate information per orbit + std::string colsys = "PbPb"; // collision system (PbPb or pp) + int intrate = -1; // Automatic IR from collision context if -1, else user-defined interaction rate in Hz + bool flat_gas = true; // if true, the gas density is considered flat in the TPC volume + unsigned int nFlatGasLoopers = 500; // number of loopers to be generated per event in case of flat gas [currently unused, kept for possible future debug developments] + float fraction_pairs = 0.08; // fraction of loopers [currently unused, kept for possible future debug developments] + float multiplier[2] = {1., 1.}; // multiplier for pairs and compton loopers for Poissonian and Gaussian sampling + unsigned int fixedNLoopers[2] = {1, 1}; // fixed number of loopers coming from pairs and compton electrons - valid if flat gas is false and both Poisson and Gaussian params files are empty + float adjust_flatgas = 0.f; // adjustment for the number of flat gas loopers per orbit (in percentage, e.g. -0.1 = -10%) [-1, inf)] O2ParamDef(GenTPCLoopersParam, "GenTPCLoopers"); }; diff --git a/Generators/share/TPCLoopers/README.md b/Generators/share/TPCLoopers/README.md new file mode 100644 index 0000000000000..0e0ac858b8809 --- /dev/null +++ b/Generators/share/TPCLoopers/README.md @@ -0,0 +1,79 @@ +# TPC Loopers Generator - Parameter Files + +This directory contains parameter files used by the TPC Loopers event generator in ALICE O2. + +## Overview + +The TPC Loopers generator uses pre-trained ONNX models to generate realistic looper particles based on machine learning models trained on full GEANT4 slow neutron transport simulations. The parameter files in this directory provide: +- Example statistical distribution parameters for sampling the number of loopers per event +- **Mandatory** scaling parameters for transforming the ONNX model outputs to physical values + +## Files Description + +### Statistical Sampling Parameters + +The files provided in the folder are examples based on the training dataset. + +#### `gaussian_params.csv` +Parameters for Gaussian distribution used to sample the number of Compton electrons per event. + +**Format:** Four values (one per line) +1. Mean (μ) +2. Standard deviation (σ) +3. Minimum value +4. Maximum value + +#### `poisson_params.csv` +Parameters for Poisson distribution used to sample the number of electron-positron pairs per event. + +**Format:** Three values (one per line) +1. Lambda (λ) parameter +2. Minimum value +3. Maximum value + +### Scaler Parameters + +These JSON files contain the parameters for inverse transformation of the ONNX models output. They should be kept as they are +unless a new version of the models is released. + +#### `ScalerComptonParams.json` +Scaler parameters for Compton electron generation model. + +**Structure:** +```json +{ + "normal": { + "min": [array of 5 min values for min-max normalization], + "max": [array of 5 max values for min-max normalization] + }, + "outlier": { + "center": [array of 2 center values for robust scaling], + "scale": [array of 2 scale values for robust scaling] + } +} +``` + +- **normal**: Min-max normalization parameters for standard features (`Px`, `Py`, `Pz`, `VertexCoordinatesX`, `VertexCoordinatesY`) +- **outlier**: Robust scaler parameters (center and scale) for outlier features (`VertexCoordinatesZ`,`time`) + +#### `ScalerPairParams.json` +Scaler parameters for electron-positron pair generation model. + +**Structure:** +```json +{ + "normal": { + "min": [array of 8 min values for min-max normalization], + "max": [array of 8 max values for min-max normalization] + }, + "outlier": { + "center": [array of 2 center values for robust scaling], + "scale": [array of 2 scale values for robust scaling] + } +} +``` + +- **normal**: Min-max normalization parameters for standard features (`Px_e`, `Py_e`, `Pz_e`,`Px_p`, `Py_p`, `Pz_p`, `VertexCoordinatesX`, `VertexCoordinatesY`) +- **outlier**: Robust scaler parameters (center and scale) for outlier features (`VertexCoordinatesZ`,`time`) +--- +*Author: M. Giacalone - September 2025* diff --git a/Generators/share/egconfig/ScalerComptonParams.json b/Generators/share/TPCLoopers/ScalerComptonParams.json similarity index 100% rename from Generators/share/egconfig/ScalerComptonParams.json rename to Generators/share/TPCLoopers/ScalerComptonParams.json diff --git a/Generators/share/egconfig/ScalerPairParams.json b/Generators/share/TPCLoopers/ScalerPairParams.json similarity index 100% rename from Generators/share/egconfig/ScalerPairParams.json rename to Generators/share/TPCLoopers/ScalerPairParams.json diff --git a/Generators/share/egconfig/gaussian_params.csv b/Generators/share/TPCLoopers/gaussian_params.csv similarity index 100% rename from Generators/share/egconfig/gaussian_params.csv rename to Generators/share/TPCLoopers/gaussian_params.csv diff --git a/Generators/share/egconfig/poisson_params.csv b/Generators/share/TPCLoopers/poisson_params.csv similarity index 100% rename from Generators/share/egconfig/poisson_params.csv rename to Generators/share/TPCLoopers/poisson_params.csv diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index ce49254799587..465a8ffb7ee22 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -25,6 +25,8 @@ #include "TParticle.h" #include "TSystem.h" #include "TGrid.h" +#include "CCDB/BasicCCDBManager.h" +#include namespace o2 { @@ -50,7 +52,7 @@ Generator::Generator() : FairGenerator("ALICEo2", "ALICEo2 Generator"), if (transport) { bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); if (tpcActive) { - if (initLoopersGen()) { + if (initTPCLoopersGen()) { mAddTPCLoopers = kTRUE; } } else { @@ -79,7 +81,7 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na if (transport) { bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); if (tpcActive) { - if (initLoopersGen()) { + if (initTPCLoopersGen()) { mAddTPCLoopers = kTRUE; } } else { @@ -94,7 +96,7 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na /*****************************************************************/ #ifdef GENERATORS_WITH_TPCLOOPERS -bool Generator::initLoopersGen() +bool Generator::initTPCLoopersGen() { // Expand all environment paths const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); @@ -169,24 +171,24 @@ bool Generator::initLoopersGen() nclxrate = isAlien[2] || isCCDB[2] ? local_names[2] : nclxrate; try { // Create the TPC loopers generator with the provided parameters - mLoopersGen = std::make_unique(model_pairs, model_compton, poisson, gauss, scaler_pair, scaler_compton); + mTPCLoopersGen = std::make_unique(model_pairs, model_compton, poisson, gauss, scaler_pair, scaler_compton); const auto& intrate = loopersParam.intrate; // Configure the generator with flat gas loopers defined per orbit with clusters/track info // If intrate is negative (default), automatic IR from collisioncontext.root will be used if (flat_gas) { - mLoopersGen->SetRate(nclxrate, (colsys == "PbPb") ? true : false, intrate); - mLoopersGen->SetAdjust(loopersParam.adjust_flatgas); + mTPCLoopersGen->SetRate(nclxrate, (colsys == "PbPb") ? true : false, intrate); + mTPCLoopersGen->SetAdjust(loopersParam.adjust_flatgas); } else { // Otherwise, Poisson+Gauss sampling or fixed number of loopers per event will be used // Multiplier is applied only with distribution sampling // This configuration can be used for testing purposes, in all other cases flat gas is recommended - mLoopersGen->SetNLoopers(nLoopersPairs, nLoopersCompton); - mLoopersGen->SetMultiplier(multiplier); + mTPCLoopersGen->SetNLoopers(nLoopersPairs, nLoopersCompton); + mTPCLoopersGen->SetMultiplier(multiplier); } LOG(info) << "TPC Loopers generator initialized successfully"; } catch (const std::exception& e) { LOG(error) << "Failed to initialize TPC Loopers generator: " << e.what(); - mLoopersGen.reset(); + mTPCLoopersGen.reset(); } return kTRUE; } @@ -210,21 +212,21 @@ Bool_t { #ifdef GENERATORS_WITH_TPCLOOPERS if (mAddTPCLoopers) { - if (!mLoopersGen) { + if (!mTPCLoopersGen) { LOG(error) << "Loopers generator not initialized"; return kFALSE; } // Generate loopers using the initialized TPC loopers generator - if (!mLoopersGen->generateEvent()) { + if (!mTPCLoopersGen->generateEvent()) { LOG(error) << "Failed to generate loopers event"; return kFALSE; } - if (mLoopersGen->getNLoopers() == 0) { + if (mTPCLoopersGen->getNLoopers() == 0) { LOG(warning) << "No loopers generated for this event"; return kTRUE; } - const auto& looperParticles = mLoopersGen->importParticles(); + const auto& looperParticles = mTPCLoopersGen->importParticles(); if (looperParticles.empty()) { LOG(error) << "Failed to import loopers particles"; return kFALSE; diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx index 8dff795de40a3..6e5af7c0c84d8 100644 --- a/Generators/src/TPCLoopers.cxx +++ b/Generators/src/TPCLoopers.cxx @@ -12,6 +12,16 @@ /// \author M+Giacalone - September 2025 #include "Generators/TPCLoopers.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsRaw/HBFUtils.h" +#include "TF1.h" +#include +#include +#include "SimulationDataFormat/MCGenProperties.h" +#include +#include +#include "TDatabasePDG.h" // Static Ort::Env instance for multiple onnx model loading Ort::Env global_env(ORT_LOGGING_LEVEL_WARNING, "GlobalEnv"); @@ -46,10 +56,11 @@ std::vector Scaler::inverse_transform(const std::vector& input) { std::vector output; for (int i = 0; i < input.size(); ++i) { - if (i < input.size() - 2) + if (i < input.size() - 2) { output.push_back(input[i] * (normal_max[i] - normal_min[i]) + normal_min[i]); - else + } else { output.push_back(input[i] * outlier_scale[i - (input.size() - 2)] + outlier_center[i - (input.size() - 2)]); + } } return output; @@ -80,8 +91,9 @@ std::vector ONNXGenerator::generate_sample() // Generate a latent vector (z) std::vector z(100); - for (auto& v : z) + for (auto& v : z) { v = rand_gen.Gaus(0.0, 1.0); + } // Prepare input tensor std::vector input_shape = {1, 100}; @@ -227,7 +239,7 @@ Bool_t GenTPCLoopers::generateEvent() return true; } -Bool_t GenTPCLoopers::generateEvent(double& time_limit) +Bool_t GenTPCLoopers::generateEvent(double time_limit) { LOG(info) << "Time constraint for loopers: " << time_limit << " ns"; // Generate pairs @@ -253,6 +265,8 @@ Bool_t GenTPCLoopers::generateEvent(double& time_limit) std::vector GenTPCLoopers::importParticles() { std::vector particles; + const double mass_e = TDatabasePDG::Instance()->GetParticle(11)->Mass(); + const double mass_p = TDatabasePDG::Instance()->GetParticle(-11)->Mass(); // Get looper pairs from the event for (auto& pair : mGenPairs) { double px_e, py_e, pz_e, px_p, py_p, pz_p; @@ -268,8 +282,8 @@ std::vector GenTPCLoopers::importParticles() vy = pair[7]; vz = pair[8]; time = pair[9]; - e_etot = TMath::Sqrt(px_e * px_e + py_e * py_e + pz_e * pz_e + mMass_e * mMass_e); - p_etot = TMath::Sqrt(px_p * px_p + py_p * py_p + pz_p * pz_p + mMass_p * mMass_p); + e_etot = TMath::Sqrt(px_e * px_e + py_e * py_e + pz_e * pz_e + mass_e * mass_e); + p_etot = TMath::Sqrt(px_p * px_p + py_p * py_p + pz_p * pz_p + mass_p * mass_p); // Push the electron TParticle electron(11, 1, -1, -1, -1, -1, px_e, py_e, pz_e, e_etot, vx, vy, vz, time / 1e9); electron.SetStatusCode(o2::mcgenstatus::MCGenStatusEncoding(electron.GetStatusCode(), 0).fullEncoding); @@ -295,7 +309,7 @@ std::vector GenTPCLoopers::importParticles() vy = compton[4]; vz = compton[5]; time = compton[6]; - etot = TMath::Sqrt(px * px + py * py + pz * pz + mMass_e * mMass_e); + etot = TMath::Sqrt(px * px + py * py + pz * pz + mass_e * mass_e); // Push the electron TParticle electron(11, 1, -1, -1, -1, -1, px, py, pz, etot, vx, vy, vz, time / 1e9); electron.SetStatusCode(o2::mcgenstatus::MCGenStatusEncoding(electron.GetStatusCode(), 0).fullEncoding); @@ -329,7 +343,7 @@ unsigned int GenTPCLoopers::GaussianElectrons() return gaussValue; } -void GenTPCLoopers::SetNLoopers(unsigned int& nsig_pair, unsigned int& nsig_compton) +void GenTPCLoopers::SetNLoopers(unsigned int nsig_pair, unsigned int nsig_compton) { if (mFlatGas) { mNLoopersPairs = nsig_pair; @@ -348,7 +362,7 @@ void GenTPCLoopers::SetNLoopers(unsigned int& nsig_pair, unsigned int& nsig_comp } } -void GenTPCLoopers::SetMultiplier(std::array& mult) +void GenTPCLoopers::SetMultiplier(const std::array& mult) { // Multipliers will work only if the poissonian and gaussian parameters are set // otherwise they will be ignored @@ -362,7 +376,7 @@ void GenTPCLoopers::SetMultiplier(std::array& mult) } } -void GenTPCLoopers::setFlatGas(Bool_t& flat, const Int_t& number = -1, const Int_t& nloopers_orbit = -1) +void GenTPCLoopers::setFlatGas(Bool_t flat, Int_t number, Int_t nloopers_orbit) { mFlatGas = flat; if (mFlatGas) { @@ -408,7 +422,7 @@ void GenTPCLoopers::setFlatGas(Bool_t& flat, const Int_t& number = -1, const Int LOG(info) << "Flat gas loopers: " << (mFlatGas ? "ON" : "OFF") << ", Reference loopers number per " << (mFlatGasOrbit ? "orbit " : "event ") << mFlatGasNumber; } -void GenTPCLoopers::setFractionPairs(float& fractionPairs) +void GenTPCLoopers::setFractionPairs(float fractionPairs) { if (fractionPairs < 0 || fractionPairs > 1) { LOG(fatal) << "Error: Loops fraction for pairs must be in the range [0, 1]."; @@ -418,7 +432,7 @@ void GenTPCLoopers::setFractionPairs(float& fractionPairs) LOG(info) << "Pairs fraction set to: " << mLoopsFractionPairs; } -void GenTPCLoopers::SetRate(const std::string& rateFile, const bool& isPbPb = true, const int& intRate = 50000) +void GenTPCLoopers::SetRate(const std::string& rateFile, bool isPbPb = true, int intRate) { // Checking if the rate file exists and is not empty TFile rate_file(rateFile.c_str(), "READ"); @@ -459,7 +473,7 @@ void GenTPCLoopers::SetRate(const std::string& rateFile, const bool& isPbPb = tr } } -void GenTPCLoopers::SetAdjust(const float& adjust = 0.f) +void GenTPCLoopers::SetAdjust(float adjust) { if (mFlatGas && mFlatGasOrbit && adjust >= -1.f && adjust != 0.f) { LOG(info) << "Adjusting flat gas number per orbit by " << adjust * 100.f << "%"; From 2a9acbed7eb2a7047b910122e6b8c8373e5a7d9b Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Mon, 5 Jan 2026 10:21:41 +0100 Subject: [PATCH 043/234] Revert "Corrected include folder" This reverts commit 1989aed2c6064aaec4d11dfaba2a08d101fed386. --- Generators/CMakeLists.txt | 19 +++-- Generators/include/Generators/Generator.h | 5 +- .../include/Generators/TPCLoopersParam.h | 35 ++++---- .../include/{Generators => }/TPCLoopers.h | 44 +++++------ Generators/share/TPCLoopers/README.md | 79 ------------------- .../ScalerComptonParams.json | 0 .../ScalerPairParams.json | 0 .../gaussian_params.csv | 0 .../poisson_params.csv | 0 Generators/src/Generator.cxx | 28 +++---- Generators/src/TPCLoopers.cxx | 40 +++------- 11 files changed, 78 insertions(+), 172 deletions(-) rename Generators/include/{Generators => }/TPCLoopers.h (71%) delete mode 100644 Generators/share/TPCLoopers/README.md rename Generators/share/{TPCLoopers => egconfig}/ScalerComptonParams.json (100%) rename Generators/share/{TPCLoopers => egconfig}/ScalerPairParams.json (100%) rename Generators/share/{TPCLoopers => egconfig}/gaussian_params.csv (100%) rename Generators/share/{TPCLoopers => egconfig}/poisson_params.csv (100%) diff --git a/Generators/CMakeLists.txt b/Generators/CMakeLists.txt index 287536ff118f7..f1921b8d8d72a 100644 --- a/Generators/CMakeLists.txt +++ b/Generators/CMakeLists.txt @@ -41,8 +41,8 @@ o2_add_library(Generators src/GeneratorTParticleParam.cxx src/GeneratorService.cxx src/FlowMapper.cxx - src/TPCLoopers.cxx - src/TPCLoopersParam.cxx + $<$:src/TPCLoopers.cxx> + $<$:src/TPCLoopersParam.cxx> $<$:src/GeneratorPythia8.cxx> $<$:src/DecayerPythia8.cxx> $<$:src/GeneratorPythia8Param.cxx> @@ -55,7 +55,7 @@ o2_add_library(Generators PUBLIC_LINK_LIBRARIES FairRoot::Base O2::SimConfig O2::CommonUtils O2::DetectorsBase O2::ZDCBase O2::SimulationDataFormat ${pythiaTarget} ${hepmcTarget} FairRoot::Gen - onnxruntime::onnxruntime + $<$:onnxruntime::onnxruntime> TARGETVARNAME targetName) if(pythia_FOUND) @@ -66,7 +66,9 @@ if(HepMC3_FOUND) target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_HEPMC3) endif() -target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_TPCLOOPERS) +if(onnxruntime_FOUND) + target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_TPCLOOPERS) +endif() set(headers include/Generators/Generator.h @@ -93,9 +95,11 @@ set(headers include/Generators/FlowMapper.h ) -list(APPEND headers - include/Generators/TPCLoopers.h - include/Generators/TPCLoopersParam.h) +if(onnxruntime_FOUND) + list(APPEND headers + include/Generators/TPCLoopers.h + include/Generators/TPCLoopersParam.h) +endif() if(pythia_FOUND) list(APPEND headers @@ -167,5 +171,4 @@ endif() o2_data_file(COPY share/external DESTINATION Generators) o2_data_file(COPY share/egconfig DESTINATION Generators) -o2_data_file(COPY share/TPCLoopers DESTINATION Generators) o2_data_file(COPY share/pythia8 DESTINATION Generators) diff --git a/Generators/include/Generators/Generator.h b/Generators/include/Generators/Generator.h index 3484601aa42bb..5a4921e036ca3 100644 --- a/Generators/include/Generators/Generator.h +++ b/Generators/include/Generators/Generator.h @@ -17,6 +17,7 @@ #include "FairGenerator.h" #include "TParticle.h" #include "Generators/Trigger.h" +#include "CCDB/BasicCCDBManager.h" #ifdef GENERATORS_WITH_TPCLOOPERS #include "Generators/TPCLoopers.h" #include "Generators/TPCLoopersParam.h" @@ -171,8 +172,8 @@ class Generator : public FairGenerator #ifdef GENERATORS_WITH_TPCLOOPERS // Loopers generator instance - std::unique_ptr mTPCLoopersGen = nullptr; - bool initTPCLoopersGen(); + std::unique_ptr mLoopersGen = nullptr; + bool initLoopersGen(); #endif ClassDefOverride(Generator, 2); diff --git a/Generators/include/Generators/TPCLoopersParam.h b/Generators/include/Generators/TPCLoopersParam.h index 87e4510d6e617..49c8e5f5927b6 100644 --- a/Generators/include/Generators/TPCLoopersParam.h +++ b/Generators/include/Generators/TPCLoopersParam.h @@ -24,27 +24,26 @@ namespace eventgen /** ** a parameter class/struct to keep the settings of - ** the TPC loopers event-generator and + ** the tpc loopers event-generator and ** allow the user to modify them **/ struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper { - bool loopersVeto = false; // if true, no loopers are generated - // Current files are set to custom user CCDB paths, TO BE CHANGED - std::string model_pairs = "ccdb://Users/m/mgiacalo/WGAN_ExtGenPair"; // ONNX model for e+e- pair production - std::string model_compton = "ccdb://Users/m/mgiacalo/WGAN_ExtGenCompton"; // ONNX model for Compton scattering - std::string poisson = "${O2_ROOT}/share/Generators/TPCLoopers/poisson_params.csv"; // file with Poissonian parameters - std::string gauss = "${O2_ROOT}/share/Generators/TPCLoopers/gaussian_params.csv"; // file with Gaussian parameters - std::string scaler_pair = "${O2_ROOT}/share/Generators/TPCLoopers/ScalerPairParams.json"; // file with scaler parameters for e+e- pair production - std::string scaler_compton = "${O2_ROOT}/share/Generators/TPCLoopers/ScalerComptonParams.json"; // file with scaler parameters for Compton scattering - std::string nclxrate = "ccdb://Users/m/mgiacalo/ClustersTrackRatio"; // file with clusters/rate information per orbit - std::string colsys = "PbPb"; // collision system (PbPb or pp) - int intrate = -1; // Automatic IR from collision context if -1, else user-defined interaction rate in Hz - bool flat_gas = true; // if true, the gas density is considered flat in the TPC volume - unsigned int nFlatGasLoopers = 500; // number of loopers to be generated per event in case of flat gas [currently unused, kept for possible future debug developments] - float fraction_pairs = 0.08; // fraction of loopers [currently unused, kept for possible future debug developments] - float multiplier[2] = {1., 1.}; // multiplier for pairs and compton loopers for Poissonian and Gaussian sampling - unsigned int fixedNLoopers[2] = {1, 1}; // fixed number of loopers coming from pairs and compton electrons - valid if flat gas is false and both Poisson and Gaussian params files are empty - float adjust_flatgas = 0.f; // adjustment for the number of flat gas loopers per orbit (in percentage, e.g. -0.1 = -10%) [-1, inf)] + bool loopersVeto = false; // if true, no loopers are generated + std::string model_pairs = "ccdb://Users/m/mgiacalo/WGAN_ExtGenPair"; // ONNX model for e+e- pair production + std::string model_compton = "ccdb://Users/m/mgiacalo/WGAN_ExtGenCompton"; // ONNX model for Compton scattering + std::string poisson = "${O2_ROOT}/share/Generators/egconfig/poisson_params.csv"; // file with Poissonian parameters + std::string gauss = "${O2_ROOT}/share/Generators/egconfig/gaussian_params.csv"; // file with Gaussian parameters + std::string scaler_pair = "${O2_ROOT}/share/Generators/egconfig/ScalerPairParams.json"; // file with scaler parameters for e+e- pair production + std::string scaler_compton = "${O2_ROOT}/share/Generators/egconfig/ScalerComptonParams.json"; // file with scaler parameters for Compton scattering + std::string nclxrate = "ccdb://Users/m/mgiacalo/ClustersTrackRatio"; // file with clusters/rate information per orbit + std::string colsys = "PbPb"; // collision system (PbPb or pp) + int intrate = -1; // Automatic IR from collision context if -1, else user-defined interaction rate in Hz + bool flat_gas = true; // if true, the gas density is considered flat in the TPC volume + unsigned int nFlatGasLoopers = 500; // number of loopers to be generated per event in case of flat gas [currently unused, kept for possible future debug developments] + float fraction_pairs = 0.08; // fraction of loopers [currently unused, kept for possible future debug developments] + float multiplier[2] = {1., 1.}; // multiplier for pairs and compton loopers for Poissonian and Gaussian sampling + unsigned int fixedNLoopers[2] = {1, 1}; // fixed number of loopers coming from pairs and compton electrons - valid if flat gas is false and both Poisson and Gaussian params files are empty + float adjust_flatgas = 0.f; // adjustment for the number of flat gas loopers per orbit (in percentage, e.g. -0.1 = -10%) [-1, inf)] O2ParamDef(GenTPCLoopersParam, "GenTPCLoopers"); }; diff --git a/Generators/include/Generators/TPCLoopers.h b/Generators/include/TPCLoopers.h similarity index 71% rename from Generators/include/Generators/TPCLoopers.h rename to Generators/include/TPCLoopers.h index 6a1d3ef262e22..57d178667b497 100644 --- a/Generators/include/Generators/TPCLoopers.h +++ b/Generators/include/TPCLoopers.h @@ -17,11 +17,21 @@ #ifdef GENERATORS_WITH_TPCLOOPERS #include #endif +#include #include +#include #include +#include "CCDB/CCDBTimeStampUtils.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsRaw/HBFUtils.h" #include "TRandom3.h" +#include "TDatabasePDG.h" #include +#include +#include "SimulationDataFormat/MCGenProperties.h" #include "TParticle.h" +#include "TF1.h" +#include #ifdef GENERATORS_WITH_TPCLOOPERS // Static Ort::Env instance for multiple onnx model loading @@ -29,8 +39,6 @@ extern Ort::Env global_env; // This class is responsible for loading the scaler parameters from a JSON file // and applying the inverse transformation to the generated data. -// Inferenced output is scaled (min-max normalization or robust scaling for outlier features) during training, -// so we need to revert this transformation to get physical values. struct Scaler { std::vector normal_min; std::vector normal_max; @@ -66,20 +74,6 @@ namespace eventgen { #ifdef GENERATORS_WITH_TPCLOOPERS -/** - * Generator for TPC Loopers based on pre-trained ONNX models. - * Currently it generates loopers as electron-positron pairs and Compton electrons - * according to specified distributions and parameters. - * This can be extended to other types of background processes in the future (e.g. slow neutron spallation products, saturation tail). - * Multiple configuration options are available: - * - Flat gas: loopers are generated uniformly per event taking a reference value which can be either the LHC orbit time or the average interaction time record interval from the collision context. - * ==> Current automatic setup (default) sets the interaction rate automatically from the collision context and the reference value per orbit is calculated from an external file. - * ==> Number of loopers per orbit can be adjusted via a specific parameter. - * - Poisson + Gaussian sampling: number of loopers are sampled from Poissonian (for pairs) and Gaussian (for Compton electrons) distributions based on provided parameters. - * ==> flat gas must be disabled to use this option. - * - Fixed number of loopers per event - * ==> flat gas must be disabled to use this option and Poissonian/Gaussian parameters file should be set to None - */ class GenTPCLoopers { public: @@ -89,7 +83,7 @@ class GenTPCLoopers Bool_t generateEvent(); - Bool_t generateEvent(double time_limit); + Bool_t generateEvent(double& time_limit); std::vector importParticles(); @@ -97,17 +91,17 @@ class GenTPCLoopers unsigned int GaussianElectrons(); - void SetNLoopers(unsigned int nsig_pair, unsigned int nsig_compton); + void SetNLoopers(unsigned int& nsig_pair, unsigned int& nsig_compton); - void SetMultiplier(const std::array& mult); + void SetMultiplier(std::array& mult); - void setFlatGas(Bool_t flat, Int_t number = -1, Int_t nloopers_orbit = -1); + void setFlatGas(Bool_t& flat, const Int_t& number, const Int_t& nloopers_orbit); - void setFractionPairs(float fractionPairs); + void setFractionPairs(float& fractionPairs); - void SetRate(const std::string& rateFile, bool isPbPb, int intRate = 50000); + void SetRate(const std::string& rateFile, const bool& isPbPb, const int& intRate); - void SetAdjust(float adjust = 0.f); + void SetAdjust(const float& adjust); unsigned int getNLoopers() const { return (mNLoopersPairs + mNLoopersCompton); } @@ -127,6 +121,10 @@ class GenTPCLoopers bool mGaussSet = false; // Random number generator TRandom3 mRandGen; + // Masses of the electrons and positrons + TDatabasePDG* mPDG = TDatabasePDG::Instance(); + double mMass_e = mPDG->GetParticle(11)->Mass(); + double mMass_p = mPDG->GetParticle(-11)->Mass(); int mCurrentEvent = 0; // Current event number, used for adaptive loopers TFile* mContextFile = nullptr; // Input collision context file o2::steer::DigitizationContext* mCollisionContext = nullptr; // Pointer to the digitization context diff --git a/Generators/share/TPCLoopers/README.md b/Generators/share/TPCLoopers/README.md deleted file mode 100644 index 0e0ac858b8809..0000000000000 --- a/Generators/share/TPCLoopers/README.md +++ /dev/null @@ -1,79 +0,0 @@ -# TPC Loopers Generator - Parameter Files - -This directory contains parameter files used by the TPC Loopers event generator in ALICE O2. - -## Overview - -The TPC Loopers generator uses pre-trained ONNX models to generate realistic looper particles based on machine learning models trained on full GEANT4 slow neutron transport simulations. The parameter files in this directory provide: -- Example statistical distribution parameters for sampling the number of loopers per event -- **Mandatory** scaling parameters for transforming the ONNX model outputs to physical values - -## Files Description - -### Statistical Sampling Parameters - -The files provided in the folder are examples based on the training dataset. - -#### `gaussian_params.csv` -Parameters for Gaussian distribution used to sample the number of Compton electrons per event. - -**Format:** Four values (one per line) -1. Mean (μ) -2. Standard deviation (σ) -3. Minimum value -4. Maximum value - -#### `poisson_params.csv` -Parameters for Poisson distribution used to sample the number of electron-positron pairs per event. - -**Format:** Three values (one per line) -1. Lambda (λ) parameter -2. Minimum value -3. Maximum value - -### Scaler Parameters - -These JSON files contain the parameters for inverse transformation of the ONNX models output. They should be kept as they are -unless a new version of the models is released. - -#### `ScalerComptonParams.json` -Scaler parameters for Compton electron generation model. - -**Structure:** -```json -{ - "normal": { - "min": [array of 5 min values for min-max normalization], - "max": [array of 5 max values for min-max normalization] - }, - "outlier": { - "center": [array of 2 center values for robust scaling], - "scale": [array of 2 scale values for robust scaling] - } -} -``` - -- **normal**: Min-max normalization parameters for standard features (`Px`, `Py`, `Pz`, `VertexCoordinatesX`, `VertexCoordinatesY`) -- **outlier**: Robust scaler parameters (center and scale) for outlier features (`VertexCoordinatesZ`,`time`) - -#### `ScalerPairParams.json` -Scaler parameters for electron-positron pair generation model. - -**Structure:** -```json -{ - "normal": { - "min": [array of 8 min values for min-max normalization], - "max": [array of 8 max values for min-max normalization] - }, - "outlier": { - "center": [array of 2 center values for robust scaling], - "scale": [array of 2 scale values for robust scaling] - } -} -``` - -- **normal**: Min-max normalization parameters for standard features (`Px_e`, `Py_e`, `Pz_e`,`Px_p`, `Py_p`, `Pz_p`, `VertexCoordinatesX`, `VertexCoordinatesY`) -- **outlier**: Robust scaler parameters (center and scale) for outlier features (`VertexCoordinatesZ`,`time`) ---- -*Author: M. Giacalone - September 2025* diff --git a/Generators/share/TPCLoopers/ScalerComptonParams.json b/Generators/share/egconfig/ScalerComptonParams.json similarity index 100% rename from Generators/share/TPCLoopers/ScalerComptonParams.json rename to Generators/share/egconfig/ScalerComptonParams.json diff --git a/Generators/share/TPCLoopers/ScalerPairParams.json b/Generators/share/egconfig/ScalerPairParams.json similarity index 100% rename from Generators/share/TPCLoopers/ScalerPairParams.json rename to Generators/share/egconfig/ScalerPairParams.json diff --git a/Generators/share/TPCLoopers/gaussian_params.csv b/Generators/share/egconfig/gaussian_params.csv similarity index 100% rename from Generators/share/TPCLoopers/gaussian_params.csv rename to Generators/share/egconfig/gaussian_params.csv diff --git a/Generators/share/TPCLoopers/poisson_params.csv b/Generators/share/egconfig/poisson_params.csv similarity index 100% rename from Generators/share/TPCLoopers/poisson_params.csv rename to Generators/share/egconfig/poisson_params.csv diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 465a8ffb7ee22..ce49254799587 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -25,8 +25,6 @@ #include "TParticle.h" #include "TSystem.h" #include "TGrid.h" -#include "CCDB/BasicCCDBManager.h" -#include namespace o2 { @@ -52,7 +50,7 @@ Generator::Generator() : FairGenerator("ALICEo2", "ALICEo2 Generator"), if (transport) { bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); if (tpcActive) { - if (initTPCLoopersGen()) { + if (initLoopersGen()) { mAddTPCLoopers = kTRUE; } } else { @@ -81,7 +79,7 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na if (transport) { bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); if (tpcActive) { - if (initTPCLoopersGen()) { + if (initLoopersGen()) { mAddTPCLoopers = kTRUE; } } else { @@ -96,7 +94,7 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na /*****************************************************************/ #ifdef GENERATORS_WITH_TPCLOOPERS -bool Generator::initTPCLoopersGen() +bool Generator::initLoopersGen() { // Expand all environment paths const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); @@ -171,24 +169,24 @@ bool Generator::initTPCLoopersGen() nclxrate = isAlien[2] || isCCDB[2] ? local_names[2] : nclxrate; try { // Create the TPC loopers generator with the provided parameters - mTPCLoopersGen = std::make_unique(model_pairs, model_compton, poisson, gauss, scaler_pair, scaler_compton); + mLoopersGen = std::make_unique(model_pairs, model_compton, poisson, gauss, scaler_pair, scaler_compton); const auto& intrate = loopersParam.intrate; // Configure the generator with flat gas loopers defined per orbit with clusters/track info // If intrate is negative (default), automatic IR from collisioncontext.root will be used if (flat_gas) { - mTPCLoopersGen->SetRate(nclxrate, (colsys == "PbPb") ? true : false, intrate); - mTPCLoopersGen->SetAdjust(loopersParam.adjust_flatgas); + mLoopersGen->SetRate(nclxrate, (colsys == "PbPb") ? true : false, intrate); + mLoopersGen->SetAdjust(loopersParam.adjust_flatgas); } else { // Otherwise, Poisson+Gauss sampling or fixed number of loopers per event will be used // Multiplier is applied only with distribution sampling // This configuration can be used for testing purposes, in all other cases flat gas is recommended - mTPCLoopersGen->SetNLoopers(nLoopersPairs, nLoopersCompton); - mTPCLoopersGen->SetMultiplier(multiplier); + mLoopersGen->SetNLoopers(nLoopersPairs, nLoopersCompton); + mLoopersGen->SetMultiplier(multiplier); } LOG(info) << "TPC Loopers generator initialized successfully"; } catch (const std::exception& e) { LOG(error) << "Failed to initialize TPC Loopers generator: " << e.what(); - mTPCLoopersGen.reset(); + mLoopersGen.reset(); } return kTRUE; } @@ -212,21 +210,21 @@ Bool_t { #ifdef GENERATORS_WITH_TPCLOOPERS if (mAddTPCLoopers) { - if (!mTPCLoopersGen) { + if (!mLoopersGen) { LOG(error) << "Loopers generator not initialized"; return kFALSE; } // Generate loopers using the initialized TPC loopers generator - if (!mTPCLoopersGen->generateEvent()) { + if (!mLoopersGen->generateEvent()) { LOG(error) << "Failed to generate loopers event"; return kFALSE; } - if (mTPCLoopersGen->getNLoopers() == 0) { + if (mLoopersGen->getNLoopers() == 0) { LOG(warning) << "No loopers generated for this event"; return kTRUE; } - const auto& looperParticles = mTPCLoopersGen->importParticles(); + const auto& looperParticles = mLoopersGen->importParticles(); if (looperParticles.empty()) { LOG(error) << "Failed to import loopers particles"; return kFALSE; diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx index 6e5af7c0c84d8..8dff795de40a3 100644 --- a/Generators/src/TPCLoopers.cxx +++ b/Generators/src/TPCLoopers.cxx @@ -12,16 +12,6 @@ /// \author M+Giacalone - September 2025 #include "Generators/TPCLoopers.h" -#include "CCDB/CCDBTimeStampUtils.h" -#include "CCDB/CcdbApi.h" -#include "DetectorsRaw/HBFUtils.h" -#include "TF1.h" -#include -#include -#include "SimulationDataFormat/MCGenProperties.h" -#include -#include -#include "TDatabasePDG.h" // Static Ort::Env instance for multiple onnx model loading Ort::Env global_env(ORT_LOGGING_LEVEL_WARNING, "GlobalEnv"); @@ -56,11 +46,10 @@ std::vector Scaler::inverse_transform(const std::vector& input) { std::vector output; for (int i = 0; i < input.size(); ++i) { - if (i < input.size() - 2) { + if (i < input.size() - 2) output.push_back(input[i] * (normal_max[i] - normal_min[i]) + normal_min[i]); - } else { + else output.push_back(input[i] * outlier_scale[i - (input.size() - 2)] + outlier_center[i - (input.size() - 2)]); - } } return output; @@ -91,9 +80,8 @@ std::vector ONNXGenerator::generate_sample() // Generate a latent vector (z) std::vector z(100); - for (auto& v : z) { + for (auto& v : z) v = rand_gen.Gaus(0.0, 1.0); - } // Prepare input tensor std::vector input_shape = {1, 100}; @@ -239,7 +227,7 @@ Bool_t GenTPCLoopers::generateEvent() return true; } -Bool_t GenTPCLoopers::generateEvent(double time_limit) +Bool_t GenTPCLoopers::generateEvent(double& time_limit) { LOG(info) << "Time constraint for loopers: " << time_limit << " ns"; // Generate pairs @@ -265,8 +253,6 @@ Bool_t GenTPCLoopers::generateEvent(double time_limit) std::vector GenTPCLoopers::importParticles() { std::vector particles; - const double mass_e = TDatabasePDG::Instance()->GetParticle(11)->Mass(); - const double mass_p = TDatabasePDG::Instance()->GetParticle(-11)->Mass(); // Get looper pairs from the event for (auto& pair : mGenPairs) { double px_e, py_e, pz_e, px_p, py_p, pz_p; @@ -282,8 +268,8 @@ std::vector GenTPCLoopers::importParticles() vy = pair[7]; vz = pair[8]; time = pair[9]; - e_etot = TMath::Sqrt(px_e * px_e + py_e * py_e + pz_e * pz_e + mass_e * mass_e); - p_etot = TMath::Sqrt(px_p * px_p + py_p * py_p + pz_p * pz_p + mass_p * mass_p); + e_etot = TMath::Sqrt(px_e * px_e + py_e * py_e + pz_e * pz_e + mMass_e * mMass_e); + p_etot = TMath::Sqrt(px_p * px_p + py_p * py_p + pz_p * pz_p + mMass_p * mMass_p); // Push the electron TParticle electron(11, 1, -1, -1, -1, -1, px_e, py_e, pz_e, e_etot, vx, vy, vz, time / 1e9); electron.SetStatusCode(o2::mcgenstatus::MCGenStatusEncoding(electron.GetStatusCode(), 0).fullEncoding); @@ -309,7 +295,7 @@ std::vector GenTPCLoopers::importParticles() vy = compton[4]; vz = compton[5]; time = compton[6]; - etot = TMath::Sqrt(px * px + py * py + pz * pz + mass_e * mass_e); + etot = TMath::Sqrt(px * px + py * py + pz * pz + mMass_e * mMass_e); // Push the electron TParticle electron(11, 1, -1, -1, -1, -1, px, py, pz, etot, vx, vy, vz, time / 1e9); electron.SetStatusCode(o2::mcgenstatus::MCGenStatusEncoding(electron.GetStatusCode(), 0).fullEncoding); @@ -343,7 +329,7 @@ unsigned int GenTPCLoopers::GaussianElectrons() return gaussValue; } -void GenTPCLoopers::SetNLoopers(unsigned int nsig_pair, unsigned int nsig_compton) +void GenTPCLoopers::SetNLoopers(unsigned int& nsig_pair, unsigned int& nsig_compton) { if (mFlatGas) { mNLoopersPairs = nsig_pair; @@ -362,7 +348,7 @@ void GenTPCLoopers::SetNLoopers(unsigned int nsig_pair, unsigned int nsig_compto } } -void GenTPCLoopers::SetMultiplier(const std::array& mult) +void GenTPCLoopers::SetMultiplier(std::array& mult) { // Multipliers will work only if the poissonian and gaussian parameters are set // otherwise they will be ignored @@ -376,7 +362,7 @@ void GenTPCLoopers::SetMultiplier(const std::array& mult) } } -void GenTPCLoopers::setFlatGas(Bool_t flat, Int_t number, Int_t nloopers_orbit) +void GenTPCLoopers::setFlatGas(Bool_t& flat, const Int_t& number = -1, const Int_t& nloopers_orbit = -1) { mFlatGas = flat; if (mFlatGas) { @@ -422,7 +408,7 @@ void GenTPCLoopers::setFlatGas(Bool_t flat, Int_t number, Int_t nloopers_orbit) LOG(info) << "Flat gas loopers: " << (mFlatGas ? "ON" : "OFF") << ", Reference loopers number per " << (mFlatGasOrbit ? "orbit " : "event ") << mFlatGasNumber; } -void GenTPCLoopers::setFractionPairs(float fractionPairs) +void GenTPCLoopers::setFractionPairs(float& fractionPairs) { if (fractionPairs < 0 || fractionPairs > 1) { LOG(fatal) << "Error: Loops fraction for pairs must be in the range [0, 1]."; @@ -432,7 +418,7 @@ void GenTPCLoopers::setFractionPairs(float fractionPairs) LOG(info) << "Pairs fraction set to: " << mLoopsFractionPairs; } -void GenTPCLoopers::SetRate(const std::string& rateFile, bool isPbPb = true, int intRate) +void GenTPCLoopers::SetRate(const std::string& rateFile, const bool& isPbPb = true, const int& intRate = 50000) { // Checking if the rate file exists and is not empty TFile rate_file(rateFile.c_str(), "READ"); @@ -473,7 +459,7 @@ void GenTPCLoopers::SetRate(const std::string& rateFile, bool isPbPb = true, int } } -void GenTPCLoopers::SetAdjust(float adjust) +void GenTPCLoopers::SetAdjust(const float& adjust = 0.f) { if (mFlatGas && mFlatGasOrbit && adjust >= -1.f && adjust != 0.f) { LOG(info) << "Adjusting flat gas number per orbit by " << adjust * 100.f << "%"; From 63794a47f05379a1a293c1ace1e64ae392d59175 Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Mon, 5 Jan 2026 10:21:41 +0100 Subject: [PATCH 044/234] Revert "Add copyright headers" This reverts commit 6837bccb95a137dd24d42d44fd4db5579ad3dbf9. --- Generators/include/TPCLoopers.h | 13 ------------- Generators/src/TPCLoopers.cxx | 13 ------------- 2 files changed, 26 deletions(-) diff --git a/Generators/include/TPCLoopers.h b/Generators/include/TPCLoopers.h index 57d178667b497..9addcf844e09d 100644 --- a/Generators/include/TPCLoopers.h +++ b/Generators/include/TPCLoopers.h @@ -1,16 +1,3 @@ -// Copyright 2024-2025 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \author M+Giacalone - September 2025 - #ifndef ALICEO2_EVENTGEN_TPCLOOPERS_H_ #define ALICEO2_EVENTGEN_TPCLOOPERS_H_ diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx index 8dff795de40a3..258b6cce07b5b 100644 --- a/Generators/src/TPCLoopers.cxx +++ b/Generators/src/TPCLoopers.cxx @@ -1,16 +1,3 @@ -// Copyright 2024-2025 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \author M+Giacalone - September 2025 - #include "Generators/TPCLoopers.h" // Static Ort::Env instance for multiple onnx model loading From 7744200e31549fbbcf8078013cbf8eb497803ef3 Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Mon, 5 Jan 2026 10:21:41 +0100 Subject: [PATCH 045/234] Revert "Please consider the following formatting changes" This reverts commit 569255b67223793d520de38f90463bc2f8ca6917. --- Generators/include/Generators/Generator.h | 2 +- .../include/Generators/TPCLoopersParam.h | 24 +- Generators/include/TPCLoopers.h | 155 +++++------ .../share/egconfig/ScalerComptonParams.json | 52 ++-- .../share/egconfig/ScalerPairParams.json | 64 ++--- Generators/src/Generator.cxx | 6 +- Generators/src/TPCLoopers.cxx | 256 ++++++++++-------- 7 files changed, 288 insertions(+), 271 deletions(-) diff --git a/Generators/include/Generators/Generator.h b/Generators/include/Generators/Generator.h index 5a4921e036ca3..67277e20736ce 100644 --- a/Generators/include/Generators/Generator.h +++ b/Generators/include/Generators/Generator.h @@ -161,7 +161,7 @@ class Generator : public FairGenerator void updateSubGeneratorInformation(o2::dataformats::MCEventHeader* header) const; // loopers flag - Bool_t mAddTPCLoopers = kFALSE; // Flag is automatically set to true if TPC is in readout detectors, loopers are not vetoed and transport is enabled + Bool_t mAddTPCLoopers = kFALSE; // Flag is automatically set to true if TPC is in readout detectors, loopers are not vetoed and transport is enabled // collect an ID and a short description of sub-generator entities std::unordered_map mSubGeneratorsIdToDesc; // the current ID of the sub-generator used in the current event (if applicable) diff --git a/Generators/include/Generators/TPCLoopersParam.h b/Generators/include/Generators/TPCLoopersParam.h index 49c8e5f5927b6..24d905c59c967 100644 --- a/Generators/include/Generators/TPCLoopersParam.h +++ b/Generators/include/Generators/TPCLoopersParam.h @@ -28,22 +28,22 @@ namespace eventgen ** allow the user to modify them **/ struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper { - bool loopersVeto = false; // if true, no loopers are generated - std::string model_pairs = "ccdb://Users/m/mgiacalo/WGAN_ExtGenPair"; // ONNX model for e+e- pair production - std::string model_compton = "ccdb://Users/m/mgiacalo/WGAN_ExtGenCompton"; // ONNX model for Compton scattering - std::string poisson = "${O2_ROOT}/share/Generators/egconfig/poisson_params.csv"; // file with Poissonian parameters - std::string gauss = "${O2_ROOT}/share/Generators/egconfig/gaussian_params.csv"; // file with Gaussian parameters - std::string scaler_pair = "${O2_ROOT}/share/Generators/egconfig/ScalerPairParams.json"; // file with scaler parameters for e+e- pair production + bool loopersVeto = false; // if true, no loopers are generated + std::string model_pairs = "ccdb://Users/m/mgiacalo/WGAN_ExtGenPair"; // ONNX model for e+e- pair production + std::string model_compton = "ccdb://Users/m/mgiacalo/WGAN_ExtGenCompton"; // ONNX model for Compton scattering + std::string poisson = "${O2_ROOT}/share/Generators/egconfig/poisson_params.csv"; // file with Poissonian parameters + std::string gauss = "${O2_ROOT}/share/Generators/egconfig/gaussian_params.csv"; // file with Gaussian parameters + std::string scaler_pair = "${O2_ROOT}/share/Generators/egconfig/ScalerPairParams.json"; // file with scaler parameters for e+e- pair production std::string scaler_compton = "${O2_ROOT}/share/Generators/egconfig/ScalerComptonParams.json"; // file with scaler parameters for Compton scattering std::string nclxrate = "ccdb://Users/m/mgiacalo/ClustersTrackRatio"; // file with clusters/rate information per orbit std::string colsys = "PbPb"; // collision system (PbPb or pp) int intrate = -1; // Automatic IR from collision context if -1, else user-defined interaction rate in Hz - bool flat_gas = true; // if true, the gas density is considered flat in the TPC volume - unsigned int nFlatGasLoopers = 500; // number of loopers to be generated per event in case of flat gas [currently unused, kept for possible future debug developments] - float fraction_pairs = 0.08; // fraction of loopers [currently unused, kept for possible future debug developments] - float multiplier[2] = {1., 1.}; // multiplier for pairs and compton loopers for Poissonian and Gaussian sampling - unsigned int fixedNLoopers[2] = {1, 1}; // fixed number of loopers coming from pairs and compton electrons - valid if flat gas is false and both Poisson and Gaussian params files are empty - float adjust_flatgas = 0.f; // adjustment for the number of flat gas loopers per orbit (in percentage, e.g. -0.1 = -10%) [-1, inf)] + bool flat_gas = true; // if true, the gas density is considered flat in the TPC volume + unsigned int nFlatGasLoopers = 500; // number of loopers to be generated per event in case of flat gas [currently unused, kept for possible future debug developments] + float fraction_pairs = 0.08; // fraction of loopers [currently unused, kept for possible future debug developments] + float multiplier[2] = {1., 1.}; // multiplier for pairs and compton loopers for Poissonian and Gaussian sampling + unsigned int fixedNLoopers[2] = {1, 1}; // fixed number of loopers coming from pairs and compton electrons - valid if flat gas is false and both Poisson and Gaussian params files are empty + float adjust_flatgas = 0.f; // adjustment for the number of flat gas loopers per orbit (in percentage, e.g. -0.1 = -10%) [-1, inf)] O2ParamDef(GenTPCLoopersParam, "GenTPCLoopers"); }; diff --git a/Generators/include/TPCLoopers.h b/Generators/include/TPCLoopers.h index 9addcf844e09d..8a4dc0030aa21 100644 --- a/Generators/include/TPCLoopers.h +++ b/Generators/include/TPCLoopers.h @@ -26,32 +26,33 @@ extern Ort::Env global_env; // This class is responsible for loading the scaler parameters from a JSON file // and applying the inverse transformation to the generated data. -struct Scaler { - std::vector normal_min; - std::vector normal_max; - std::vector outlier_center; - std::vector outlier_scale; +struct Scaler +{ + std::vector normal_min; + std::vector normal_max; + std::vector outlier_center; + std::vector outlier_scale; - void load(const std::string& filename); + void load(const std::string &filename); - std::vector inverse_transform(const std::vector& input); + std::vector inverse_transform(const std::vector &input); - private: - std::vector jsonArrayToVector(const rapidjson::Value& jsonArray); +private: + std::vector jsonArrayToVector(const rapidjson::Value &jsonArray); }; // This class loads the ONNX model and generates samples using it. class ONNXGenerator { - public: - ONNXGenerator(Ort::Env& shared_env, const std::string& model_path); +public: + ONNXGenerator(Ort::Env &shared_env, const std::string &model_path); - std::vector generate_sample(); + std::vector generate_sample(); - private: - Ort::Env& env; - Ort::Session session; - TRandom3 rand_gen; +private: + Ort::Env &env; + Ort::Session session; + TRandom3 rand_gen; }; #endif // GENERATORS_WITH_TPCLOOPERS @@ -63,67 +64,67 @@ namespace eventgen #ifdef GENERATORS_WITH_TPCLOOPERS class GenTPCLoopers { - public: - GenTPCLoopers(std::string model_pairs = "tpcloopmodel.onnx", std::string model_compton = "tpcloopmodelcompton.onnx", - std::string poisson = "poisson.csv", std::string gauss = "gauss.csv", std::string scaler_pair = "scaler_pair.json", - std::string scaler_compton = "scaler_compton.json"); - - Bool_t generateEvent(); - - Bool_t generateEvent(double& time_limit); - - std::vector importParticles(); - - unsigned int PoissonPairs(); - - unsigned int GaussianElectrons(); - - void SetNLoopers(unsigned int& nsig_pair, unsigned int& nsig_compton); - - void SetMultiplier(std::array& mult); - - void setFlatGas(Bool_t& flat, const Int_t& number, const Int_t& nloopers_orbit); - - void setFractionPairs(float& fractionPairs); - - void SetRate(const std::string& rateFile, const bool& isPbPb, const int& intRate); - - void SetAdjust(const float& adjust); - - unsigned int getNLoopers() const { return (mNLoopersPairs + mNLoopersCompton); } - - private: - std::unique_ptr mONNX_pair = nullptr; - std::unique_ptr mONNX_compton = nullptr; - std::unique_ptr mScaler_pair = nullptr; - std::unique_ptr mScaler_compton = nullptr; - double mPoisson[3] = {0.0, 0.0, 0.0}; // Mu, Min and Max of Poissonian - double mGauss[4] = {0.0, 0.0, 0.0, 0.0}; // Mean, Std, Min, Max - std::vector> mGenPairs; - std::vector> mGenElectrons; - unsigned int mNLoopersPairs = -1; - unsigned int mNLoopersCompton = -1; - std::array mMultiplier = {1., 1.}; - bool mPoissonSet = false; - bool mGaussSet = false; - // Random number generator - TRandom3 mRandGen; - // Masses of the electrons and positrons - TDatabasePDG* mPDG = TDatabasePDG::Instance(); - double mMass_e = mPDG->GetParticle(11)->Mass(); - double mMass_p = mPDG->GetParticle(-11)->Mass(); - int mCurrentEvent = 0; // Current event number, used for adaptive loopers - TFile* mContextFile = nullptr; // Input collision context file - o2::steer::DigitizationContext* mCollisionContext = nullptr; // Pointer to the digitization context - std::vector mInteractionTimeRecords; // Interaction time records from collision context - Bool_t mFlatGas = false; // Flag to indicate if flat gas loopers are used - Bool_t mFlatGasOrbit = false; // Flag to indicate if flat gas loopers are per orbit - Int_t mFlatGasNumber = -1; // Number of flat gas loopers per event - double mIntTimeRecMean = 1.0; // Average interaction time record used for the reference - double mTimeLimit = 0.0; // Time limit for the current event - double mTimeEnd = 0.0; // Time limit for the last event - float mLoopsFractionPairs = 0.08; // Fraction of loopers from Pairs - int mInteractionRate = 50000; // Interaction rate in Hz + public: + GenTPCLoopers(std::string model_pairs = "tpcloopmodel.onnx", std::string model_compton = "tpcloopmodelcompton.onnx", + std::string poisson = "poisson.csv", std::string gauss = "gauss.csv", std::string scaler_pair = "scaler_pair.json", + std::string scaler_compton = "scaler_compton.json"); + + Bool_t generateEvent(); + + Bool_t generateEvent(double &time_limit); + + std::vector importParticles(); + + unsigned int PoissonPairs(); + + unsigned int GaussianElectrons(); + + void SetNLoopers(unsigned int &nsig_pair, unsigned int &nsig_compton); + + void SetMultiplier(std::array &mult); + + void setFlatGas(Bool_t& flat, const Int_t& number, const Int_t& nloopers_orbit); + + void setFractionPairs(float &fractionPairs); + + void SetRate(const std::string &rateFile, const bool &isPbPb, const int &intRate); + + void SetAdjust(const float &adjust); + + unsigned int getNLoopers() const { return (mNLoopersPairs + mNLoopersCompton); } + + private: + std::unique_ptr mONNX_pair = nullptr; + std::unique_ptr mONNX_compton = nullptr; + std::unique_ptr mScaler_pair = nullptr; + std::unique_ptr mScaler_compton = nullptr; + double mPoisson[3] = {0.0, 0.0, 0.0}; // Mu, Min and Max of Poissonian + double mGauss[4] = {0.0, 0.0, 0.0, 0.0}; // Mean, Std, Min, Max + std::vector> mGenPairs; + std::vector> mGenElectrons; + unsigned int mNLoopersPairs = -1; + unsigned int mNLoopersCompton = -1; + std::array mMultiplier = {1., 1.}; + bool mPoissonSet = false; + bool mGaussSet = false; + // Random number generator + TRandom3 mRandGen; + // Masses of the electrons and positrons + TDatabasePDG *mPDG = TDatabasePDG::Instance(); + double mMass_e = mPDG->GetParticle(11)->Mass(); + double mMass_p = mPDG->GetParticle(-11)->Mass(); + int mCurrentEvent = 0; // Current event number, used for adaptive loopers + TFile *mContextFile = nullptr; // Input collision context file + o2::steer::DigitizationContext *mCollisionContext = nullptr; // Pointer to the digitization context + std::vector mInteractionTimeRecords; // Interaction time records from collision context + Bool_t mFlatGas = false; // Flag to indicate if flat gas loopers are used + Bool_t mFlatGasOrbit = false; // Flag to indicate if flat gas loopers are per orbit + Int_t mFlatGasNumber = -1; // Number of flat gas loopers per event + double mIntTimeRecMean = 1.0; // Average interaction time record used for the reference + double mTimeLimit = 0.0; // Time limit for the current event + double mTimeEnd = 0.0; // Time limit for the last event + float mLoopsFractionPairs = 0.08; // Fraction of loopers from Pairs + int mInteractionRate = 50000; // Interaction rate in Hz }; #endif // GENERATORS_WITH_TPCLOOPERS diff --git a/Generators/share/egconfig/ScalerComptonParams.json b/Generators/share/egconfig/ScalerComptonParams.json index 157647fee2db7..d8e654847f46e 100644 --- a/Generators/share/egconfig/ScalerComptonParams.json +++ b/Generators/share/egconfig/ScalerComptonParams.json @@ -1,28 +1,28 @@ { - "normal": { - "min": [ - -0.0108811147511005, - -0.0098758740350604, - -0.0103233363479375, - -260.0542297363281, - -259.80059814453125 - ], - "max": [ - 0.0108060473576188, - 0.0103057539090514, - 0.0106524610891938, - 260.0343933105469, - 259.62890625 - ] - }, - "outlier": { - "center": [ - -71.39387130737305, - 96791.23828125 - ], - "scale": [ - 265.9389114379883, - 230762.30981445312 - ] - } + "normal": { + "min": [ + -0.0108811147511005, + -0.0098758740350604, + -0.0103233363479375, + -260.0542297363281, + -259.80059814453125 + ], + "max": [ + 0.0108060473576188, + 0.0103057539090514, + 0.0106524610891938, + 260.0343933105469, + 259.62890625 + ] + }, + "outlier": { + "center": [ + -71.39387130737305, + 96791.23828125 + ], + "scale": [ + 265.9389114379883, + 230762.30981445312 + ] + } } \ No newline at end of file diff --git a/Generators/share/egconfig/ScalerPairParams.json b/Generators/share/egconfig/ScalerPairParams.json index 57cdac421d3f6..61434bfa2462e 100644 --- a/Generators/share/egconfig/ScalerPairParams.json +++ b/Generators/share/egconfig/ScalerPairParams.json @@ -1,34 +1,34 @@ { - "normal": { - "min": [ - -0.0073022879660129, - -0.0077305701561272, - -0.0076750442385673, - -0.0082916170358657, - -0.0079681202769279, - -0.0077468422241508, - -255.6164093017578, - -252.9441680908203 - ], - "max": [ - 0.007688719779253, - 0.0077241472899913, - 0.0075828479602932, - 0.00813714787364, - 0.0083825681358575, - 0.0073839174583554, - 256.2904968261719, - 253.4925842285156 - ] - }, - "outlier": { - "center": [ - -79.66580963134766, - 141535.640625 - ], - "scale": [ - 250.8921127319336, - 222363.16015625 - ] - } + "normal": { + "min": [ + -0.0073022879660129, + -0.0077305701561272, + -0.0076750442385673, + -0.0082916170358657, + -0.0079681202769279, + -0.0077468422241508, + -255.6164093017578, + -252.9441680908203 + ], + "max": [ + 0.007688719779253, + 0.0077241472899913, + 0.0075828479602932, + 0.00813714787364, + 0.0083825681358575, + 0.0073839174583554, + 256.2904968261719, + 253.4925842285156 + ] + }, + "outlier": { + "center": [ + -79.66580963134766, + 141535.640625 + ], + "scale": [ + 250.8921127319336, + 222363.16015625 + ] + } } \ No newline at end of file diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index ce49254799587..9c16c0dfb7e92 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -170,7 +170,7 @@ bool Generator::initLoopersGen() try { // Create the TPC loopers generator with the provided parameters mLoopersGen = std::make_unique(model_pairs, model_compton, poisson, gauss, scaler_pair, scaler_compton); - const auto& intrate = loopersParam.intrate; + const auto &intrate = loopersParam.intrate; // Configure the generator with flat gas loopers defined per orbit with clusters/track info // If intrate is negative (default), automatic IR from collisioncontext.root will be used if (flat_gas) { @@ -209,7 +209,7 @@ Bool_t Generator::finalizeEvent() { #ifdef GENERATORS_WITH_TPCLOOPERS - if (mAddTPCLoopers) { + if(mAddTPCLoopers) { if (!mLoopersGen) { LOG(error) << "Loopers generator not initialized"; return kFALSE; @@ -268,7 +268,7 @@ Bool_t } /** Event finalization**/ - if (!finalizeEvent()) { + if(!finalizeEvent()) { LOG(error) << "ReadEvent failed in finalizeEvent"; return kFALSE; } diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx index 258b6cce07b5b..ac1123b8d0bbd 100644 --- a/Generators/src/TPCLoopers.cxx +++ b/Generators/src/TPCLoopers.cxx @@ -6,7 +6,7 @@ Ort::Env global_env(ORT_LOGGING_LEVEL_WARNING, "GlobalEnv"); // This class is responsible for loading the scaler parameters from a JSON file // and applying the inverse transformation to the generated data. -void Scaler::load(const std::string& filename) +void Scaler::load(const std::string &filename) { std::ifstream file(filename); if (!file.is_open()) { @@ -27,73 +27,76 @@ void Scaler::load(const std::string& filename) normal_max = jsonArrayToVector(doc["normal"]["max"]); outlier_center = jsonArrayToVector(doc["outlier"]["center"]); outlier_scale = jsonArrayToVector(doc["outlier"]["scale"]); -} +} -std::vector Scaler::inverse_transform(const std::vector& input) +std::vector Scaler::inverse_transform(const std::vector &input) { - std::vector output; - for (int i = 0; i < input.size(); ++i) { - if (i < input.size() - 2) - output.push_back(input[i] * (normal_max[i] - normal_min[i]) + normal_min[i]); - else - output.push_back(input[i] * outlier_scale[i - (input.size() - 2)] + outlier_center[i - (input.size() - 2)]); - } + std::vector output; + for (int i = 0; i < input.size(); ++i) + { + if (i < input.size() - 2) + output.push_back(input[i] * (normal_max[i] - normal_min[i]) + normal_min[i]); + else + output.push_back(input[i] * outlier_scale[i - (input.size() - 2)] + outlier_center[i - (input.size() - 2)]); + } - return output; + return output; } -std::vector Scaler::jsonArrayToVector(const rapidjson::Value& jsonArray) +std::vector Scaler::jsonArrayToVector(const rapidjson::Value &jsonArray) { - std::vector vec; - for (int i = 0; i < jsonArray.Size(); ++i) { - vec.push_back(jsonArray[i].GetDouble()); - } - return vec; + std::vector vec; + for (int i = 0; i < jsonArray.Size(); ++i) + { + vec.push_back(jsonArray[i].GetDouble()); + } + return vec; } // This class loads the ONNX model and generates samples using it. ONNXGenerator::ONNXGenerator(Ort::Env& shared_env, const std::string& model_path) - : env(shared_env), session(env, model_path.c_str(), Ort::SessionOptions{}) +: env(shared_env), session(env, model_path.c_str(), Ort::SessionOptions{}) { - // Create session options - Ort::SessionOptions session_options; - session = Ort::Session(env, model_path.c_str(), session_options); + // Create session options + Ort::SessionOptions session_options; + session = Ort::Session(env, model_path.c_str(), session_options); } std::vector ONNXGenerator::generate_sample() { - Ort::AllocatorWithDefaultOptions allocator; - - // Generate a latent vector (z) - std::vector z(100); - for (auto& v : z) - v = rand_gen.Gaus(0.0, 1.0); - - // Prepare input tensor - std::vector input_shape = {1, 100}; - // Get memory information - Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); - - // Create input tensor correctly - Ort::Value input_tensor = Ort::Value::CreateTensor( - memory_info, z.data(), z.size(), input_shape.data(), input_shape.size()); - // Run inference - const char* input_names[] = {"z"}; - const char* output_names[] = {"output"}; - auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_names, &input_tensor, 1, output_names, 1); - - // Extract output - float* output_data = output_tensors.front().GetTensorMutableData(); - // Get the size of the output tensor - auto output_tensor_info = output_tensors.front().GetTensorTypeAndShapeInfo(); - size_t output_data_size = output_tensor_info.GetElementCount(); // Total number of elements in the tensor - std::vector output; - for (int i = 0; i < output_data_size; ++i) { - output.push_back(output_data[i]); - } + Ort::AllocatorWithDefaultOptions allocator; + + // Generate a latent vector (z) + std::vector z(100); + for (auto &v : z) + v = rand_gen.Gaus(0.0, 1.0); + + // Prepare input tensor + std::vector input_shape = {1, 100}; + // Get memory information + Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); + + // Create input tensor correctly + Ort::Value input_tensor = Ort::Value::CreateTensor( + memory_info, z.data(), z.size(), input_shape.data(), input_shape.size()); + // Run inference + const char *input_names[] = {"z"}; + const char *output_names[] = {"output"}; + auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_names, &input_tensor, 1, output_names, 1); + + // Extract output + float *output_data = output_tensors.front().GetTensorMutableData(); + // Get the size of the output tensor + auto output_tensor_info = output_tensors.front().GetTensorTypeAndShapeInfo(); + size_t output_data_size = output_tensor_info.GetElementCount(); // Total number of elements in the tensor + std::vector output; + for (int i = 0; i < output_data_size; ++i) + { + output.push_back(output_data[i]); + } - return output; + return output; } namespace o2 @@ -102,67 +105,79 @@ namespace eventgen { GenTPCLoopers::GenTPCLoopers(std::string model_pairs, std::string model_compton, - std::string poisson, std::string gauss, std::string scaler_pair, - std::string scaler_compton) + std::string poisson, std::string gauss, std::string scaler_pair, + std::string scaler_compton) { - // Checking if the model files exist and are not empty - std::ifstream model_file[2]; - model_file[0].open(model_pairs); - model_file[1].open(model_compton); - if (!model_file[0].is_open() || model_file[0].peek() == std::ifstream::traits_type::eof()) { - LOG(fatal) << "Error: Pairs model file is empty or does not exist!"; - exit(1); - } - if (!model_file[1].is_open() || model_file[1].peek() == std::ifstream::traits_type::eof()) { - LOG(fatal) << "Error: Compton model file is empty or does not exist!"; - exit(1); - } - model_file[0].close(); - model_file[1].close(); - // Checking if the scaler files exist and are not empty - std::ifstream scaler_file[2]; - scaler_file[0].open(scaler_pair); - scaler_file[1].open(scaler_compton); - if (!scaler_file[0].is_open() || scaler_file[0].peek() == std::ifstream::traits_type::eof()) { - LOG(fatal) << "Error: Pairs scaler file is empty or does not exist!"; - exit(1); - } - if (!scaler_file[1].is_open() || scaler_file[1].peek() == std::ifstream::traits_type::eof()) { - LOG(fatal) << "Error: Compton scaler file is empty or does not exist!"; - exit(1); - } - scaler_file[0].close(); - scaler_file[1].close(); - // Checking if the poisson file exists and it's not empty - if (poisson != "" && poisson != "None" && poisson != "none") { - std::ifstream poisson_file(poisson); - if (!poisson_file.is_open() || poisson_file.peek() == std::ifstream::traits_type::eof()) { - LOG(fatal) << "Error: Poisson file is empty or does not exist!"; - exit(1); - } else { - poisson_file >> mPoisson[0] >> mPoisson[1] >> mPoisson[2]; - poisson_file.close(); - mPoissonSet = true; + // Checking if the model files exist and are not empty + std::ifstream model_file[2]; + model_file[0].open(model_pairs); + model_file[1].open(model_compton); + if (!model_file[0].is_open() || model_file[0].peek() == std::ifstream::traits_type::eof()) + { + LOG(fatal) << "Error: Pairs model file is empty or does not exist!"; + exit(1); } - } - // Checking if the gauss file exists and it's not empty - if (gauss != "" && gauss != "None" && gauss != "none") { - std::ifstream gauss_file(gauss); - if (!gauss_file.is_open() || gauss_file.peek() == std::ifstream::traits_type::eof()) { - LOG(fatal) << "Error: Gauss file is empty or does not exist!"; - exit(1); - } else { - gauss_file >> mGauss[0] >> mGauss[1] >> mGauss[2] >> mGauss[3]; - gauss_file.close(); - mGaussSet = true; + if (!model_file[1].is_open() || model_file[1].peek() == std::ifstream::traits_type::eof()) + { + LOG(fatal) << "Error: Compton model file is empty or does not exist!"; + exit(1); } - } - mONNX_pair = std::make_unique(global_env, model_pairs); - mScaler_pair = std::make_unique(); - mScaler_pair->load(scaler_pair); - mONNX_compton = std::make_unique(global_env, model_compton); - mScaler_compton = std::make_unique(); - mScaler_compton->load(scaler_compton); + model_file[0].close(); + model_file[1].close(); + // Checking if the scaler files exist and are not empty + std::ifstream scaler_file[2]; + scaler_file[0].open(scaler_pair); + scaler_file[1].open(scaler_compton); + if (!scaler_file[0].is_open() || scaler_file[0].peek() == std::ifstream::traits_type::eof()) + { + LOG(fatal) << "Error: Pairs scaler file is empty or does not exist!"; + exit(1); + } + if (!scaler_file[1].is_open() || scaler_file[1].peek() == std::ifstream::traits_type::eof()) + { + LOG(fatal) << "Error: Compton scaler file is empty or does not exist!"; + exit(1); + } + scaler_file[0].close(); + scaler_file[1].close(); + // Checking if the poisson file exists and it's not empty + if (poisson != "" && poisson != "None" && poisson != "none") + { + std::ifstream poisson_file(poisson); + if (!poisson_file.is_open() || poisson_file.peek() == std::ifstream::traits_type::eof()) + { + LOG(fatal) << "Error: Poisson file is empty or does not exist!"; + exit(1); + } + else + { + poisson_file >> mPoisson[0] >> mPoisson[1] >> mPoisson[2]; + poisson_file.close(); + mPoissonSet = true; + } + } + // Checking if the gauss file exists and it's not empty + if (gauss != "" && gauss != "None" && gauss != "none") + { + std::ifstream gauss_file(gauss); + if (!gauss_file.is_open() || gauss_file.peek() == std::ifstream::traits_type::eof()) + { + LOG(fatal) << "Error: Gauss file is empty or does not exist!"; + exit(1); + } + else + { + gauss_file >> mGauss[0] >> mGauss[1] >> mGauss[2] >> mGauss[3]; + gauss_file.close(); + mGaussSet = true; + } + } + mONNX_pair = std::make_unique(global_env, model_pairs); + mScaler_pair = std::make_unique(); + mScaler_pair->load(scaler_pair); + mONNX_compton = std::make_unique(global_env, model_compton); + mScaler_compton = std::make_unique(); + mScaler_compton->load(scaler_compton); } Bool_t GenTPCLoopers::generateEvent() @@ -337,16 +352,17 @@ void GenTPCLoopers::SetNLoopers(unsigned int& nsig_pair, unsigned int& nsig_comp void GenTPCLoopers::SetMultiplier(std::array& mult) { - // Multipliers will work only if the poissonian and gaussian parameters are set - // otherwise they will be ignored - if (mult[0] < 0 || mult[1] < 0) { - LOG(fatal) << "Error: Multiplier values must be non-negative!"; - exit(1); - } else { - LOG(info) << "Multiplier values set to: Pair = " << mult[0] << ", Compton = " << mult[1]; - mMultiplier[0] = mult[0]; - mMultiplier[1] = mult[1]; - } + // Multipliers will work only if the poissonian and gaussian parameters are set + // otherwise they will be ignored + if (mult[0] < 0 || mult[1] < 0) + { + LOG(fatal) << "Error: Multiplier values must be non-negative!"; + exit(1); + } else { + LOG(info) << "Multiplier values set to: Pair = " << mult[0] << ", Compton = " << mult[1]; + mMultiplier[0] = mult[0]; + mMultiplier[1] = mult[1]; + } } void GenTPCLoopers::setFlatGas(Bool_t& flat, const Int_t& number = -1, const Int_t& nloopers_orbit = -1) @@ -405,7 +421,7 @@ void GenTPCLoopers::setFractionPairs(float& fractionPairs) LOG(info) << "Pairs fraction set to: " << mLoopsFractionPairs; } -void GenTPCLoopers::SetRate(const std::string& rateFile, const bool& isPbPb = true, const int& intRate = 50000) +void GenTPCLoopers::SetRate(const std::string &rateFile, const bool &isPbPb = true, const int &intRate = 50000) { // Checking if the rate file exists and is not empty TFile rate_file(rateFile.c_str(), "READ"); From 755d43950918deebb1559ef7cb3480d796b2a428 Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Mon, 5 Jan 2026 10:21:41 +0100 Subject: [PATCH 046/234] Revert "Improved logging + colsys check" This reverts commit e7a790b31d71d01e91a2a40123327febda65905f. --- Generators/src/Generator.cxx | 31 +++++++++++-------------------- Generators/src/TPCLoopers.cxx | 6 ++---- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 9c16c0dfb7e92..9e083913c3bc7 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -50,15 +50,11 @@ Generator::Generator() : FairGenerator("ALICEo2", "ALICEo2 Generator"), if (transport) { bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); if (tpcActive) { - if (initLoopersGen()) { + if(initLoopersGen()){ mAddTPCLoopers = kTRUE; } - } else { - LOG(info) << "TPC not active in readout detectors: loopers fast generator disabled."; } } - } else { - LOG(info) << "Loopers fast generator turned OFF with veto flag."; } #endif } @@ -82,12 +78,8 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na if (initLoopersGen()) { mAddTPCLoopers = kTRUE; } - } else { - LOG(info) << "TPC not active in readout detectors: loopers fast generator disabled."; } } - } else { - LOG(info) << "Loopers fast generator turned OFF with veto flag."; } #endif } @@ -105,14 +97,8 @@ bool Generator::initLoopersGen() const auto& scaler_compton = gSystem->ExpandPathName(loopersParam.scaler_compton.c_str()); const auto& poisson = gSystem->ExpandPathName(loopersParam.poisson.c_str()); const auto& gauss = gSystem->ExpandPathName(loopersParam.gauss.c_str()); - const auto& flat_gas = loopersParam.flat_gas; - const auto& colsys = loopersParam.colsys; + auto flat_gas = loopersParam.flat_gas; if (flat_gas) { - if (colsys != "PbPb" && colsys != "pp") { - LOG(warning) << "Automatic background loopers configuration supports only 'pp' and 'PbPb' systems."; - LOG(warning) << "Fast loopers generator will remain OFF."; - return kFALSE; - } bool isContext = std::filesystem::exists("collisioncontext.root"); if (!isContext) { LOG(warning) << "Warning: No collisioncontext.root file found!"; @@ -170,12 +156,17 @@ bool Generator::initLoopersGen() try { // Create the TPC loopers generator with the provided parameters mLoopersGen = std::make_unique(model_pairs, model_compton, poisson, gauss, scaler_pair, scaler_compton); - const auto &intrate = loopersParam.intrate; + auto& colsys = loopersParam.colsys; + auto &intrate = loopersParam.intrate; // Configure the generator with flat gas loopers defined per orbit with clusters/track info - // If intrate is negative (default), automatic IR from collisioncontext.root will be used if (flat_gas) { - mLoopersGen->SetRate(nclxrate, (colsys == "PbPb") ? true : false, intrate); - mLoopersGen->SetAdjust(loopersParam.adjust_flatgas); + if (colsys != "PbPb" && colsys != "pp") { + LOG(fatal) << "Error: collision system must be either 'PbPb' or 'pp'"; + exit(1); + } else { + mLoopersGen->SetRate(nclxrate, (colsys == "PbPb") ? true : false, intrate); + mLoopersGen->SetAdjust(loopersParam.adjust_flatgas); + } } else { // Otherwise, Poisson+Gauss sampling or fixed number of loopers per event will be used // Multiplier is applied only with distribution sampling diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx index ac1123b8d0bbd..07af5b25f99f9 100644 --- a/Generators/src/TPCLoopers.cxx +++ b/Generators/src/TPCLoopers.cxx @@ -141,7 +141,7 @@ GenTPCLoopers::GenTPCLoopers(std::string model_pairs, std::string model_compton, scaler_file[0].close(); scaler_file[1].close(); // Checking if the poisson file exists and it's not empty - if (poisson != "" && poisson != "None" && poisson != "none") + if (poisson != "") { std::ifstream poisson_file(poisson); if (!poisson_file.is_open() || poisson_file.peek() == std::ifstream::traits_type::eof()) @@ -157,7 +157,7 @@ GenTPCLoopers::GenTPCLoopers(std::string model_pairs, std::string model_compton, } } // Checking if the gauss file exists and it's not empty - if (gauss != "" && gauss != "None" && gauss != "none") + if (gauss != "") { std::ifstream gauss_file(gauss); if (!gauss_file.is_open() || gauss_file.peek() == std::ifstream::traits_type::eof()) @@ -205,11 +205,9 @@ Bool_t GenTPCLoopers::generateEvent() // Set number of loopers if poissonian params are available if (mPoissonSet) { mNLoopersPairs = static_cast(std::round(mMultiplier[0] * PoissonPairs())); - LOG(debug) << "Generated loopers pairs (Poisson): " << mNLoopersPairs; } if (mGaussSet) { mNLoopersCompton = static_cast(std::round(mMultiplier[1] * GaussianElectrons())); - LOG(debug) << "Generated compton electrons (Gauss): " << mNLoopersCompton; } // Generate pairs for (int i = 0; i < mNLoopersPairs; ++i) { From 208f9eac7a888ee407fa18f3e475901a53d6c571 Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Mon, 5 Jan 2026 10:21:41 +0100 Subject: [PATCH 047/234] Revert "Fixed bug + cleaned code" This reverts commit b48d4ec35cdb9252783a46916898d4bfbac928f3. --- Generators/include/Generators/TPCLoopersParam.h | 4 ++-- Generators/src/Generator.cxx | 4 +++- Generators/src/TPCLoopers.cxx | 4 ++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Generators/include/Generators/TPCLoopersParam.h b/Generators/include/Generators/TPCLoopersParam.h index 24d905c59c967..74c3cf4cff0ad 100644 --- a/Generators/include/Generators/TPCLoopersParam.h +++ b/Generators/include/Generators/TPCLoopersParam.h @@ -39,8 +39,8 @@ struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper multiplier = {loopersParam.multiplier[0], loopersParam.multiplier[1]}; unsigned int nLoopersPairs = loopersParam.fixedNLoopers[0]; unsigned int nLoopersCompton = loopersParam.fixedNLoopers[1]; @@ -168,7 +170,7 @@ bool Generator::initLoopersGen() mLoopersGen->SetAdjust(loopersParam.adjust_flatgas); } } else { - // Otherwise, Poisson+Gauss sampling or fixed number of loopers per event will be used + // Otherwise, Poisson+Gauss sampling or fixed number of loopers will be used // Multiplier is applied only with distribution sampling // This configuration can be used for testing purposes, in all other cases flat gas is recommended mLoopersGen->SetNLoopers(nLoopersPairs, nLoopersCompton); diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx index 07af5b25f99f9..0fb76fcd8c3a9 100644 --- a/Generators/src/TPCLoopers.cxx +++ b/Generators/src/TPCLoopers.cxx @@ -27,6 +27,10 @@ void Scaler::load(const std::string &filename) normal_max = jsonArrayToVector(doc["normal"]["max"]); outlier_center = jsonArrayToVector(doc["outlier"]["center"]); outlier_scale = jsonArrayToVector(doc["outlier"]["scale"]); + std::vector normal_min; + std::vector normal_max; + std::vector outlier_center; + std::vector outlier_scale; } std::vector Scaler::inverse_transform(const std::vector &input) From 6baae3eaf5599d35a2e24ca3a909d22baf808e89 Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Mon, 5 Jan 2026 10:21:41 +0100 Subject: [PATCH 048/234] Revert "Set automatic interaction rate from collision context" This reverts commit a6f60e12edf933dbeb724b9ba7c51a4c5e49cffc. --- .../include/Generators/TPCLoopersParam.h | 4 ++-- Generators/include/TPCLoopers.h | 3 --- Generators/src/Generator.cxx | 10 +++++----- Generators/src/TPCLoopers.cxx | 19 ++----------------- 4 files changed, 9 insertions(+), 27 deletions(-) diff --git a/Generators/include/Generators/TPCLoopersParam.h b/Generators/include/Generators/TPCLoopersParam.h index 74c3cf4cff0ad..8571013cdec48 100644 --- a/Generators/include/Generators/TPCLoopersParam.h +++ b/Generators/include/Generators/TPCLoopersParam.h @@ -37,9 +37,9 @@ struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper mONNX_pair = nullptr; std::unique_ptr mONNX_compton = nullptr; @@ -124,7 +122,6 @@ class GenTPCLoopers double mTimeLimit = 0.0; // Time limit for the current event double mTimeEnd = 0.0; // Time limit for the last event float mLoopsFractionPairs = 0.08; // Fraction of loopers from Pairs - int mInteractionRate = 50000; // Interaction rate in Hz }; #endif // GENERATORS_WITH_TPCLOOPERS diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 18e28e4cc2668..fea1a38f1a146 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -107,7 +107,7 @@ bool Generator::initLoopersGen() } } const auto& nFlatGasLoopers = loopersParam.nFlatGasLoopers; - const auto& fraction_pairs = loopersParam.fraction_pairs; + auto fraction_pairs = loopersParam.fraction_pairs; std::array multiplier = {loopersParam.multiplier[0], loopersParam.multiplier[1]}; unsigned int nLoopersPairs = loopersParam.fixedNLoopers[0]; unsigned int nLoopersCompton = loopersParam.fixedNLoopers[1]; @@ -166,6 +166,10 @@ bool Generator::initLoopersGen() LOG(fatal) << "Error: collision system must be either 'PbPb' or 'pp'"; exit(1); } else { + if (intrate <= 0) { + LOG(fatal) << "Error: interaction rate must be positive!"; + exit(1); + } mLoopersGen->SetRate(nclxrate, (colsys == "PbPb") ? true : false, intrate); mLoopersGen->SetAdjust(loopersParam.adjust_flatgas); } @@ -213,10 +217,6 @@ Bool_t LOG(error) << "Failed to generate loopers event"; return kFALSE; } - if (mLoopersGen->getNLoopers() == 0) { - LOG(warning) << "No loopers generated for this event"; - return kTRUE; - } const auto& looperParticles = mLoopersGen->importParticles(); if (looperParticles.empty()) { LOG(error) << "Failed to import loopers particles"; diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx index 0fb76fcd8c3a9..b771b53ed33d2 100644 --- a/Generators/src/TPCLoopers.cxx +++ b/Generators/src/TPCLoopers.cxx @@ -437,28 +437,13 @@ void GenTPCLoopers::SetRate(const std::string &rateFile, const bool &isPbPb = tr LOG(fatal) << "Error: Could not find fit function '" << fitName << "' in rate file!"; exit(1); } - mInteractionRate = intRate; - if (mInteractionRate < 0) { - mContextFile = std::filesystem::exists("collisioncontext.root") ? TFile::Open("collisioncontext.root") : nullptr; - if (!mContextFile || mContextFile->IsZombie()) { - LOG(fatal) << "Error: Interaction rate not provided and collision context file not found!"; - exit(1); - } - mCollisionContext = (o2::steer::DigitizationContext*)mContextFile->Get("DigitizationContext"); - mInteractionRate = std::floor(mCollisionContext->getDigitizerInteractionRate()); - LOG(info) << "Interaction rate retrieved from collision context: " << mInteractionRate << " Hz"; - if (mInteractionRate < 0) { - LOG(fatal) << "Error: Invalid interaction rate retrieved from collision context!"; - exit(1); - } - } - auto ref = static_cast(std::floor(fit->Eval(mInteractionRate / 1000.))); // fit expects rate in kHz + auto ref = static_cast(std::floor(fit->Eval(intRate / 1000.))); // fit expects rate in kHz rate_file.Close(); if (ref <= 0) { LOG(fatal) << "Computed flat gas number reference per orbit is <=0"; exit(1); } else { - LOG(info) << "Set flat gas number to " << ref << " loopers per orbit using " << fitName << " from " << mInteractionRate << " Hz interaction rate."; + LOG(info) << "Set flat gas number to " << ref << " loopers per orbit using " << fitName << " from " << intRate << " Hz interaction rate."; auto flat = true; setFlatGas(flat, -1, ref); } From c035dd9e71953c8829c7afbdd5a7596061b006c0 Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Mon, 5 Jan 2026 10:21:41 +0100 Subject: [PATCH 049/234] Revert "Implemented rate and collision system dependence (default)" This reverts commit 32c0f318ec9737e7c1718c373d3c9660ddff477c. --- .../include/Generators/TPCLoopersParam.h | 4 -- Generators/include/TPCLoopers.h | 8 +-- Generators/src/Generator.cxx | 28 +++----- Generators/src/TPCLoopers.cxx | 64 +++---------------- 4 files changed, 17 insertions(+), 87 deletions(-) diff --git a/Generators/include/Generators/TPCLoopersParam.h b/Generators/include/Generators/TPCLoopersParam.h index 8571013cdec48..9430f4e05ac6e 100644 --- a/Generators/include/Generators/TPCLoopersParam.h +++ b/Generators/include/Generators/TPCLoopersParam.h @@ -35,15 +35,11 @@ struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper #include "SimulationDataFormat/MCGenProperties.h" #include "TParticle.h" -#include "TF1.h" #include #ifdef GENERATORS_WITH_TPCLOOPERS @@ -83,14 +82,10 @@ class GenTPCLoopers void SetMultiplier(std::array &mult); - void setFlatGas(Bool_t& flat, const Int_t& number, const Int_t& nloopers_orbit); + void setFlatGas(Bool_t &flat, const Int_t &number = -1); void setFractionPairs(float &fractionPairs); - void SetRate(const std::string &rateFile, const bool &isPbPb, const int &intRate); - - void SetAdjust(const float &adjust); - private: std::unique_ptr mONNX_pair = nullptr; std::unique_ptr mONNX_compton = nullptr; @@ -116,7 +111,6 @@ class GenTPCLoopers o2::steer::DigitizationContext *mCollisionContext = nullptr; // Pointer to the digitization context std::vector mInteractionTimeRecords; // Interaction time records from collision context Bool_t mFlatGas = false; // Flag to indicate if flat gas loopers are used - Bool_t mFlatGasOrbit = false; // Flag to indicate if flat gas loopers are per orbit Int_t mFlatGasNumber = -1; // Number of flat gas loopers per event double mIntTimeRecMean = 1.0; // Average interaction time record used for the reference double mTimeLimit = 0.0; // Time limit for the current event diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index fea1a38f1a146..50b11c0c7bb53 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -92,7 +92,6 @@ bool Generator::initLoopersGen() const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); std::string model_pairs = gSystem->ExpandPathName(loopersParam.model_pairs.c_str()); std::string model_compton = gSystem->ExpandPathName(loopersParam.model_compton.c_str()); - std::string nclxrate = gSystem->ExpandPathName(loopersParam.nclxrate.c_str()); const auto& scaler_pair = gSystem->ExpandPathName(loopersParam.scaler_pair.c_str()); const auto& scaler_compton = gSystem->ExpandPathName(loopersParam.scaler_compton.c_str()); const auto& poisson = gSystem->ExpandPathName(loopersParam.poisson.c_str()); @@ -111,10 +110,10 @@ bool Generator::initLoopersGen() std::array multiplier = {loopersParam.multiplier[0], loopersParam.multiplier[1]}; unsigned int nLoopersPairs = loopersParam.fixedNLoopers[0]; unsigned int nLoopersCompton = loopersParam.fixedNLoopers[1]; - const std::array models = {model_pairs, model_compton, nclxrate}; - const std::array local_names = {"WGANpair.onnx", "WGANcompton.onnx", "nclxrate.root"}; - const std::array isAlien = {models[0].starts_with("alien://"), models[1].starts_with("alien://"), models[2].starts_with("alien://")}; - const std::array isCCDB = {models[0].starts_with("ccdb://"), models[1].starts_with("ccdb://"), models[2].starts_with("ccdb://")}; + const std::array models = {model_pairs, model_compton}; + const std::array local_names = {"WGANpair.onnx", "WGANcompton.onnx"}; + const std::array isAlien = {models[0].starts_with("alien://"), models[1].starts_with("alien://")}; + const std::array isCCDB = {models[0].starts_with("ccdb://"), models[1].starts_with("ccdb://")}; if (std::any_of(isAlien.begin(), isAlien.end(), [](bool v) { return v; })) { if (!gGrid) { TGrid::Connect("alien://"); @@ -154,25 +153,14 @@ bool Generator::initLoopersGen() } model_pairs = isAlien[0] || isCCDB[0] ? local_names[0] : model_pairs; model_compton = isAlien[1] || isCCDB[1] ? local_names[1] : model_compton; - nclxrate = isAlien[2] || isCCDB[2] ? local_names[2] : nclxrate; try { // Create the TPC loopers generator with the provided parameters mLoopersGen = std::make_unique(model_pairs, model_compton, poisson, gauss, scaler_pair, scaler_compton); - auto& colsys = loopersParam.colsys; - auto &intrate = loopersParam.intrate; - // Configure the generator with flat gas loopers defined per orbit with clusters/track info + + // Configure the generator with flat gas loopers if enabled (default) if (flat_gas) { - if (colsys != "PbPb" && colsys != "pp") { - LOG(fatal) << "Error: collision system must be either 'PbPb' or 'pp'"; - exit(1); - } else { - if (intrate <= 0) { - LOG(fatal) << "Error: interaction rate must be positive!"; - exit(1); - } - mLoopersGen->SetRate(nclxrate, (colsys == "PbPb") ? true : false, intrate); - mLoopersGen->SetAdjust(loopersParam.adjust_flatgas); - } + mLoopersGen->setFlatGas(flat_gas, nFlatGasLoopers); + mLoopersGen->setFractionPairs(fraction_pairs); } else { // Otherwise, Poisson+Gauss sampling or fixed number of loopers will be used // Multiplier is applied only with distribution sampling diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx index b771b53ed33d2..109461ab71dfa 100644 --- a/Generators/src/TPCLoopers.cxx +++ b/Generators/src/TPCLoopers.cxx @@ -197,8 +197,7 @@ Bool_t GenTPCLoopers::generateEvent() LOG(debug) << "Current time offset wrt BC: " << mInteractionTimeRecords[mCurrentEvent].getTimeOffsetWrtBC() << " ns"; mTimeLimit = (mCurrentEvent < mInteractionTimeRecords.size() - 1) ? mInteractionTimeRecords[mCurrentEvent + 1].bc2ns() - mInteractionTimeRecords[mCurrentEvent].bc2ns() : mTimeEnd - mInteractionTimeRecords[mCurrentEvent].bc2ns(); // With flat gas the number of loopers are adapted based on time interval widths - // The denominator is either the LHC orbit (if mFlatGasOrbit is true) or the mean interaction time record interval - nLoopers = mFlatGasOrbit ? (mFlatGasNumber * (mTimeLimit / o2::constants::lhc::LHCOrbitNS)) : (mFlatGasNumber * (mTimeLimit / mIntTimeRecMean)); + nLoopers = mFlatGasNumber * (mTimeLimit / mIntTimeRecMean); nLoopersPairs = static_cast(std::round(nLoopers * mLoopsFractionPairs)); nLoopersCompton = nLoopers - nLoopersPairs; SetNLoopers(nLoopersPairs, nLoopersCompton); @@ -367,34 +366,22 @@ void GenTPCLoopers::SetMultiplier(std::array& mult) } } -void GenTPCLoopers::setFlatGas(Bool_t& flat, const Int_t& number = -1, const Int_t& nloopers_orbit = -1) +void GenTPCLoopers::setFlatGas(Bool_t& flat, const Int_t& number) { mFlatGas = flat; if (mFlatGas) { - if (nloopers_orbit > 0) { - mFlatGasOrbit = true; - mFlatGasNumber = nloopers_orbit; - LOG(info) << "Flat gas loopers will be generated using orbit reference."; + if (number < 0) { + LOG(warn) << "Warning: Number of loopers per event must be non-negative! Switching option off."; + mFlatGas = false; + mFlatGasNumber = -1; } else { - mFlatGasOrbit = false; - if (number < 0) { - LOG(warn) << "Warning: Number of loopers per event must be non-negative! Switching option off."; - mFlatGas = false; - mFlatGasNumber = -1; - } else { - mFlatGasNumber = number; - } - } - if (mFlatGas) { + mFlatGasNumber = number; mContextFile = std::filesystem::exists("collisioncontext.root") ? TFile::Open("collisioncontext.root") : nullptr; mCollisionContext = mContextFile ? (o2::steer::DigitizationContext*)mContextFile->Get("DigitizationContext") : nullptr; mInteractionTimeRecords = mCollisionContext ? mCollisionContext->getEventRecords() : std::vector{}; if (mInteractionTimeRecords.empty()) { LOG(error) << "Error: No interaction time records found in the collision context!"; exit(1); - } else { - LOG(info) << "Interaction Time records has " << mInteractionTimeRecords.size() << " entries."; - mCollisionContext->printCollisionSummary(); } for (int c = 0; c < mInteractionTimeRecords.size() - 1; c++) { mIntTimeRecMean += mInteractionTimeRecords[c + 1].bc2ns() - mInteractionTimeRecords[c].bc2ns(); @@ -410,7 +397,7 @@ void GenTPCLoopers::setFlatGas(Bool_t& flat, const Int_t& number = -1, const Int } else { mFlatGasNumber = -1; } - LOG(info) << "Flat gas loopers: " << (mFlatGas ? "ON" : "OFF") << ", Reference loopers number per " << (mFlatGasOrbit ? "orbit " : "event ") << mFlatGasNumber; + LOG(info) << "Flat gas loopers: " << (mFlatGas ? "ON" : "OFF") << ", Reference loopers number per event: " << mFlatGasNumber; } void GenTPCLoopers::setFractionPairs(float& fractionPairs) @@ -423,40 +410,5 @@ void GenTPCLoopers::setFractionPairs(float& fractionPairs) LOG(info) << "Pairs fraction set to: " << mLoopsFractionPairs; } -void GenTPCLoopers::SetRate(const std::string &rateFile, const bool &isPbPb = true, const int &intRate = 50000) -{ - // Checking if the rate file exists and is not empty - TFile rate_file(rateFile.c_str(), "READ"); - if (!rate_file.IsOpen() || rate_file.IsZombie()) { - LOG(fatal) << "Error: Rate file is empty or does not exist!"; - exit(1); - } - const char* fitName = isPbPb ? "fitPbPb" : "fitpp"; - auto fit = (TF1*)rate_file.Get(fitName); - if (!fit) { - LOG(fatal) << "Error: Could not find fit function '" << fitName << "' in rate file!"; - exit(1); - } - auto ref = static_cast(std::floor(fit->Eval(intRate / 1000.))); // fit expects rate in kHz - rate_file.Close(); - if (ref <= 0) { - LOG(fatal) << "Computed flat gas number reference per orbit is <=0"; - exit(1); - } else { - LOG(info) << "Set flat gas number to " << ref << " loopers per orbit using " << fitName << " from " << intRate << " Hz interaction rate."; - auto flat = true; - setFlatGas(flat, -1, ref); - } -} - -void GenTPCLoopers::SetAdjust(const float& adjust = 0.f) -{ - if (mFlatGas && mFlatGasOrbit && adjust >= -1.f && adjust != 0.f) { - LOG(info) << "Adjusting flat gas number per orbit by " << adjust * 100.f << "%"; - mFlatGasNumber = static_cast(std::round(mFlatGasNumber * (1.f + adjust))); - LOG(info) << "New flat gas number per orbit: " << mFlatGasNumber; - } -} - } // namespace eventgen } // namespace o2 \ No newline at end of file From fdce0869312a4e2c1a77a82b7c60c68e77bf203e Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Mon, 5 Jan 2026 10:21:41 +0100 Subject: [PATCH 050/234] Revert "Vetoing loopers for FlatGas and \!collisioncontext" This reverts commit 8f8606a66c8499de6df999795d595f3dbab9e5b3. --- Generators/include/Generators/Generator.h | 2 +- Generators/src/Generator.cxx | 21 +++++---------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/Generators/include/Generators/Generator.h b/Generators/include/Generators/Generator.h index 67277e20736ce..4b68112517893 100644 --- a/Generators/include/Generators/Generator.h +++ b/Generators/include/Generators/Generator.h @@ -173,7 +173,7 @@ class Generator : public FairGenerator #ifdef GENERATORS_WITH_TPCLOOPERS // Loopers generator instance std::unique_ptr mLoopersGen = nullptr; - bool initLoopersGen(); + void initLoopersGen(); #endif ClassDefOverride(Generator, 2); diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 50b11c0c7bb53..6fc9f378148d3 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -50,9 +50,8 @@ Generator::Generator() : FairGenerator("ALICEo2", "ALICEo2 Generator"), if (transport) { bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); if (tpcActive) { - if(initLoopersGen()){ - mAddTPCLoopers = kTRUE; - } + mAddTPCLoopers = kTRUE; + initLoopersGen(); } } } @@ -75,9 +74,8 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na if (transport) { bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); if (tpcActive) { - if (initLoopersGen()) { - mAddTPCLoopers = kTRUE; - } + mAddTPCLoopers = kTRUE; + initLoopersGen(); } } } @@ -86,7 +84,7 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na /*****************************************************************/ #ifdef GENERATORS_WITH_TPCLOOPERS -bool Generator::initLoopersGen() +void Generator::initLoopersGen() { // Expand all environment paths const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); @@ -97,14 +95,6 @@ bool Generator::initLoopersGen() const auto& poisson = gSystem->ExpandPathName(loopersParam.poisson.c_str()); const auto& gauss = gSystem->ExpandPathName(loopersParam.gauss.c_str()); auto flat_gas = loopersParam.flat_gas; - if (flat_gas) { - bool isContext = std::filesystem::exists("collisioncontext.root"); - if (!isContext) { - LOG(warning) << "Warning: No collisioncontext.root file found!"; - LOG(warning) << "Loopers will be kept OFF."; - return kFALSE; - } - } const auto& nFlatGasLoopers = loopersParam.nFlatGasLoopers; auto fraction_pairs = loopersParam.fraction_pairs; std::array multiplier = {loopersParam.multiplier[0], loopersParam.multiplier[1]}; @@ -173,7 +163,6 @@ bool Generator::initLoopersGen() LOG(error) << "Failed to initialize TPC Loopers generator: " << e.what(); mLoopersGen.reset(); } - return kTRUE; } #endif From d1a8157599ca1ce2ba45dc133210908b0f85583b Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Mon, 5 Jan 2026 10:21:41 +0100 Subject: [PATCH 051/234] Revert "Various improvements" This reverts commit 4b6530fbc6a93963de72035d123b6666b2991e32. --- .../SimConfig/include/SimConfig/SimConfig.h | 3 + Common/SimConfig/src/SimConfig.cxx | 2 + Generators/CMakeLists.txt | 4 +- Generators/include/Generators/Generator.h | 11 +- .../include/Generators/TPCLoopersParam.h | 5 +- Generators/include/TPCLoopers.h | 12 +- Generators/src/Generator.cxx | 392 +++++++++--------- Generators/src/GeneratorsLinkDef.h | 2 +- Generators/src/TPCLoopers.cxx | 3 + 9 files changed, 220 insertions(+), 214 deletions(-) diff --git a/Common/SimConfig/include/SimConfig/SimConfig.h b/Common/SimConfig/include/SimConfig/SimConfig.h index be88d9fbd8c33..8642a0e5bc225 100644 --- a/Common/SimConfig/include/SimConfig/SimConfig.h +++ b/Common/SimConfig/include/SimConfig/SimConfig.h @@ -52,6 +52,7 @@ struct SimConfigData { std::vector mActiveModules; // list of active modules std::vector mReadoutDetectors; // list of readout detectors std::string mMCEngine; // chosen VMC engine + bool mNoLoopers = false; // Disable automatic TPC loopers std::string mGenerator; // chosen VMC generator std::string mTrigger; // chosen VMC generator trigger unsigned int mNEvents; // number of events to be simulated @@ -138,6 +139,8 @@ class SimConfig // get selected active detectors std::vector const& getActiveModules() const { return mConfigData.mActiveModules; } std::vector const& getReadoutDetectors() const { return mConfigData.mReadoutDetectors; } + // get loopers veto + bool getLoopersVeto() const { return mConfigData.mNoLoopers; } // static helper functions to determine list of active / readout modules // can also be used from outside diff --git a/Common/SimConfig/src/SimConfig.cxx b/Common/SimConfig/src/SimConfig.cxx index 15879687872d5..5ddc3199e3d4a 100644 --- a/Common/SimConfig/src/SimConfig.cxx +++ b/Common/SimConfig/src/SimConfig.cxx @@ -74,6 +74,7 @@ void SimConfig::initOptions(boost::program_options::options_description& options "run", bpo::value()->default_value(-1), "ALICE run number")( "asservice", bpo::value()->default_value(false), "run in service/server mode")( "noGeant", bpo::bool_switch(), "prohibits any Geant transport/physics (by using tight cuts)")( + "noLoopers", bpo::bool_switch(), "disable automatic TPC loopers")( "forwardKine", bpo::bool_switch(), "forward kinematics on a FairMQ channel")( "noDiscOutput", bpo::bool_switch(), "switch off writing sim results to disc (useful in combination with forwardKine)"); options.add_options()("fromCollContext", bpo::value()->default_value(""), "Use a pregenerated collision context to infer number of events to simulate, how to embedd them, the vertex position etc. Takes precedence of other options such as \"--nEvents\". The format is COLLISIONCONTEXTFILE.root[:SIGNALNAME] where SIGNALNAME is the event part in the context which is relevant."); @@ -297,6 +298,7 @@ bool SimConfig::resetFromParsedMap(boost::program_options::variables_map const& using o2::detectors::DetID; mConfigData.mMCEngine = vm["mcEngine"].as(); mConfigData.mNoGeant = vm["noGeant"].as(); + mConfigData.mNoLoopers = vm["noLoopers"].as(); // Reset modules and detectors as they are anyway re-parsed mConfigData.mReadoutDetectors.clear(); diff --git a/Generators/CMakeLists.txt b/Generators/CMakeLists.txt index f1921b8d8d72a..56fe8b8fc2284 100644 --- a/Generators/CMakeLists.txt +++ b/Generators/CMakeLists.txt @@ -67,7 +67,7 @@ if(HepMC3_FOUND) endif() if(onnxruntime_FOUND) - target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_TPCLOOPERS) + target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_ONNXRUNTIME) endif() set(headers @@ -96,7 +96,7 @@ set(headers ) if(onnxruntime_FOUND) - list(APPEND headers + list(APPEND headers include/Generators/TPCLoopers.h include/Generators/TPCLoopersParam.h) endif() diff --git a/Generators/include/Generators/Generator.h b/Generators/include/Generators/Generator.h index 4b68112517893..374d53f324399 100644 --- a/Generators/include/Generators/Generator.h +++ b/Generators/include/Generators/Generator.h @@ -17,8 +17,7 @@ #include "FairGenerator.h" #include "TParticle.h" #include "Generators/Trigger.h" -#include "CCDB/BasicCCDBManager.h" -#ifdef GENERATORS_WITH_TPCLOOPERS +#ifdef GENERATORS_WITH_ONNXRUNTIME #include "Generators/TPCLoopers.h" #include "Generators/TPCLoopersParam.h" #endif @@ -78,7 +77,7 @@ class Generator : public FairGenerator /** methods to override **/ virtual Bool_t generateEvent() = 0; // generates event (in structure internal to generator) virtual Bool_t importParticles() = 0; // fills the mParticles vector (transfer from generator state) - Bool_t finalizeEvent(); // final part of event generation that can be customised using external macros + Bool_t loopers(); // adds loopers to the event in case TPC is used virtual void updateHeader(o2::dataformats::MCEventHeader* eventHeader) {}; Bool_t triggerEvent(); @@ -161,7 +160,7 @@ class Generator : public FairGenerator void updateSubGeneratorInformation(o2::dataformats::MCEventHeader* header) const; // loopers flag - Bool_t mAddTPCLoopers = kFALSE; // Flag is automatically set to true if TPC is in readout detectors, loopers are not vetoed and transport is enabled + Bool_t mAddLoopers = kFALSE; // collect an ID and a short description of sub-generator entities std::unordered_map mSubGeneratorsIdToDesc; // the current ID of the sub-generator used in the current event (if applicable) @@ -170,11 +169,11 @@ class Generator : public FairGenerator // global static information about (upper limit of) number of events to be generated static unsigned int gTotalNEvents; -#ifdef GENERATORS_WITH_TPCLOOPERS +#ifdef GENERATORS_WITH_ONNXRUNTIME // Loopers generator instance std::unique_ptr mLoopersGen = nullptr; - void initLoopersGen(); #endif + void initLoopersGen(); ClassDefOverride(Generator, 2); diff --git a/Generators/include/Generators/TPCLoopersParam.h b/Generators/include/Generators/TPCLoopersParam.h index 9430f4e05ac6e..ceeea201538b2 100644 --- a/Generators/include/Generators/TPCLoopersParam.h +++ b/Generators/include/Generators/TPCLoopersParam.h @@ -28,7 +28,6 @@ namespace eventgen ** allow the user to modify them **/ struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper { - bool loopersVeto = false; // if true, no loopers are generated std::string model_pairs = "ccdb://Users/m/mgiacalo/WGAN_ExtGenPair"; // ONNX model for e+e- pair production std::string model_compton = "ccdb://Users/m/mgiacalo/WGAN_ExtGenCompton"; // ONNX model for Compton scattering std::string poisson = "${O2_ROOT}/share/Generators/egconfig/poisson_params.csv"; // file with Poissonian parameters @@ -38,8 +37,8 @@ struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper multiplier = {1., 1.}; // multiplier for pairs and compton loopers for Poissonian and Gaussian sampling + std::array fixedNLoopers = {1, 1}; // fixed number of loopers coming from pairs and compton electrons - valid if flat gas is false and both Poisson and Gaussian params files are empty O2ParamDef(GenTPCLoopersParam, "GenTPCLoopers"); }; diff --git a/Generators/include/TPCLoopers.h b/Generators/include/TPCLoopers.h index 1c1f3585eb3ab..70146a82baf60 100644 --- a/Generators/include/TPCLoopers.h +++ b/Generators/include/TPCLoopers.h @@ -1,7 +1,7 @@ #ifndef ALICEO2_EVENTGEN_TPCLOOPERS_H_ #define ALICEO2_EVENTGEN_TPCLOOPERS_H_ -#ifdef GENERATORS_WITH_TPCLOOPERS +#ifdef GENERATORS_WITH_ONNXRUNTIME #include #endif #include @@ -19,10 +19,12 @@ #include "TParticle.h" #include -#ifdef GENERATORS_WITH_TPCLOOPERS +#ifdef GENERATORS_WITH_ONNXRUNTIME // Static Ort::Env instance for multiple onnx model loading extern Ort::Env global_env; +#endif +#ifdef GENERATORS_WITH_ONNXRUNTIME // This class is responsible for loading the scaler parameters from a JSON file // and applying the inverse transformation to the generated data. struct Scaler @@ -53,14 +55,14 @@ class ONNXGenerator Ort::Session session; TRandom3 rand_gen; }; -#endif // GENERATORS_WITH_TPCLOOPERS +#endif // GENERATORS_WITH_ONNXRUNTIME namespace o2 { namespace eventgen { -#ifdef GENERATORS_WITH_TPCLOOPERS +#ifdef GENERATORS_WITH_ONNXRUNTIME class GenTPCLoopers { public: @@ -117,7 +119,7 @@ class GenTPCLoopers double mTimeEnd = 0.0; // Time limit for the last event float mLoopsFractionPairs = 0.08; // Fraction of loopers from Pairs }; -#endif // GENERATORS_WITH_TPCLOOPERS +#endif // GENERATORS_WITH_ONNXRUNTIME } // namespace eventgen } // namespace o2 diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 6fc9f378148d3..153ef5cd5e35e 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -42,20 +42,18 @@ Generator::Generator() : FairGenerator("ALICEo2", "ALICEo2 Generator"), /** default constructor **/ mThisInstanceID = Generator::InstanceCounter; Generator::InstanceCounter++; -#ifdef GENERATORS_WITH_TPCLOOPERS - const auto& simConfig = o2::conf::SimConfig::Instance(); - const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); - if (!loopersParam.loopersVeto) { + auto simConfig = o2::conf::SimConfig::Instance(); + auto noLoops = simConfig.getLoopersVeto(); + if (!noLoops) { bool transport = (simConfig.getMCEngine() != "O2TrivialMCEngine"); if (transport) { bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); if (tpcActive) { - mAddTPCLoopers = kTRUE; + mAddLoopers = kTRUE; initLoopersGen(); } } } -#endif } /*****************************************************************/ @@ -66,26 +64,25 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na /** constructor **/ mThisInstanceID = Generator::InstanceCounter; Generator::InstanceCounter++; -#ifdef GENERATORS_WITH_TPCLOOPERS - const auto& simConfig = o2::conf::SimConfig::Instance(); - const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); - if (!loopersParam.loopersVeto) { + auto simConfig = o2::conf::SimConfig::Instance(); + auto noLoops = simConfig.getLoopersVeto(); + if (!noLoops) { bool transport = (simConfig.getMCEngine() != "O2TrivialMCEngine"); if (transport) { bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); if (tpcActive) { - mAddTPCLoopers = kTRUE; + mAddLoopers = kTRUE; initLoopersGen(); } } } -#endif } /*****************************************************************/ -#ifdef GENERATORS_WITH_TPCLOOPERS + void Generator::initLoopersGen() { +#ifdef GENERATORS_WITH_ONNXRUNTIME // Expand all environment paths const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); std::string model_pairs = gSystem->ExpandPathName(loopersParam.model_pairs.c_str()); @@ -97,9 +94,8 @@ void Generator::initLoopersGen() auto flat_gas = loopersParam.flat_gas; const auto& nFlatGasLoopers = loopersParam.nFlatGasLoopers; auto fraction_pairs = loopersParam.fraction_pairs; - std::array multiplier = {loopersParam.multiplier[0], loopersParam.multiplier[1]}; - unsigned int nLoopersPairs = loopersParam.fixedNLoopers[0]; - unsigned int nLoopersCompton = loopersParam.fixedNLoopers[1]; + auto multiplier = loopersParam.multiplier; + auto fixedNLoopers = loopersParam.fixedNLoopers; const std::array models = {model_pairs, model_compton}; const std::array local_names = {"WGANpair.onnx", "WGANcompton.onnx"}; const std::array isAlien = {models[0].starts_with("alien://"), models[1].starts_with("alien://")}; @@ -120,10 +116,8 @@ void Generator::initLoopersGen() } } if (std::any_of(isCCDB.begin(), isCCDB.end(), [](bool v) { return v; })) { - auto& ccdb = o2::ccdb::BasicCCDBManager::instance(); - ccdb.setURL("http://alice-ccdb.cern.ch"); - // Get underlying CCDB API from BasicCCDBManager - auto& ccdb_api = ccdb.getCCDBAccessor(); + o2::ccdb::CcdbApi ccdb_api; + ccdb_api.init("http://alice-ccdb.cern.ch"); for (size_t i = 0; i < models.size(); ++i) { if (isCCDB[i]) { auto model_path = models[i].substr(7); // Remove "ccdb://" @@ -155,7 +149,7 @@ void Generator::initLoopersGen() // Otherwise, Poisson+Gauss sampling or fixed number of loopers will be used // Multiplier is applied only with distribution sampling // This configuration can be used for testing purposes, in all other cases flat gas is recommended - mLoopersGen->SetNLoopers(nLoopersPairs, nLoopersCompton); + mLoopersGen->SetNLoopers(fixedNLoopers[0], fixedNLoopers[1]); mLoopersGen->SetMultiplier(multiplier); } LOG(info) << "TPC Loopers generator initialized successfully"; @@ -163,8 +157,10 @@ void Generator::initLoopersGen() LOG(error) << "Failed to initialize TPC Loopers generator: " << e.what(); mLoopersGen.reset(); } -} +#else + LOG(warn) << "ONNX Runtime support not available, cannot initialize TPC loopers generator"; #endif +} /*****************************************************************/ @@ -180,228 +176,230 @@ Bool_t /*****************************************************************/ Bool_t - Generator::finalizeEvent() + Generator::loopers() { -#ifdef GENERATORS_WITH_TPCLOOPERS - if(mAddTPCLoopers) { - if (!mLoopersGen) { - LOG(error) << "Loopers generator not initialized"; - return kFALSE; - } - - // Generate loopers using the initialized TPC loopers generator - if (!mLoopersGen->generateEvent()) { - LOG(error) << "Failed to generate loopers event"; - return kFALSE; - } - const auto& looperParticles = mLoopersGen->importParticles(); - if (looperParticles.empty()) { - LOG(error) << "Failed to import loopers particles"; - return kFALSE; - } - // Append the generated looper particles to the main particle list - mParticles.insert(mParticles.end(), looperParticles.begin(), looperParticles.end()); +#ifdef GENERATORS_WITH_ONNXRUNTIME + if (!mLoopersGen) { + LOG(error) << "Loopers generator not initialized"; + return kFALSE; + } - LOG(debug) << "Added " << looperParticles.size() << " looper particles"; + // Generate loopers using the initialized TPC loopers generator + if (!mLoopersGen->generateEvent()) { + LOG(error) << "Failed to generate loopers event"; + return kFALSE; } -#endif + const auto& looperParticles = mLoopersGen->importParticles(); + if (looperParticles.empty()) { + LOG(error) << "Failed to import loopers particles"; + return kFALSE; + } + // Append the generated looper particles to the main particle list + mParticles.insert(mParticles.end(), looperParticles.begin(), looperParticles.end()); + + LOG(debug) << "Added " << looperParticles.size() << " looper particles"; + return kTRUE; +#else + LOG(warn) << "ONNX Runtime support not available, skipping TPC loopers generation"; return kTRUE; +#endif } + /*****************************************************************/ -/*****************************************************************/ + Bool_t + Generator::ReadEvent(FairPrimaryGenerator * primGen) + { + /** read event **/ -Bool_t - Generator::ReadEvent(FairPrimaryGenerator* primGen) -{ - /** read event **/ + /** endless generate-and-trigger loop **/ + while (true) { + mReadEventCounter++; - /** endless generate-and-trigger loop **/ - while (true) { - mReadEventCounter++; + /** clear particle vector **/ + mParticles.clear(); - /** clear particle vector **/ - mParticles.clear(); + /** reset the sub-generator ID **/ + mSubGeneratorId = -1; - /** reset the sub-generator ID **/ - mSubGeneratorId = -1; + /** generate event **/ + if (!generateEvent()) { + LOG(error) << "ReadEvent failed in generateEvent"; + return kFALSE; + } - /** generate event **/ - if (!generateEvent()) { - LOG(error) << "ReadEvent failed in generateEvent"; - return kFALSE; - } + /** import particles **/ + if (!importParticles()) { + LOG(error) << "ReadEvent failed in importParticles"; + return kFALSE; + } - /** import particles **/ - if (!importParticles()) { - LOG(error) << "ReadEvent failed in importParticles"; - return kFALSE; - } + /** Add loopers **/ + if(mAddLoopers){ + if (!loopers()) { + LOG(error) << "ReadEvent failed in loopers"; + return kFALSE; + } + } - /** Event finalization**/ - if(!finalizeEvent()) { - LOG(error) << "ReadEvent failed in finalizeEvent"; - return kFALSE; - } + if (mSubGeneratorsIdToDesc.empty() && mSubGeneratorId > -1) { + LOG(fatal) << "ReadEvent failed because no SubGenerator description given"; + } - if (mSubGeneratorsIdToDesc.empty() && mSubGeneratorId > -1) { - LOG(fatal) << "ReadEvent failed because no SubGenerator description given"; - } + if (!mSubGeneratorsIdToDesc.empty() && mSubGeneratorId < 0) { + LOG(fatal) << "ReadEvent failed because SubGenerator description given but sub-generator not set"; + } - if (!mSubGeneratorsIdToDesc.empty() && mSubGeneratorId < 0) { - LOG(fatal) << "ReadEvent failed because SubGenerator description given but sub-generator not set"; + /** trigger event **/ + if (triggerEvent()) { + mTriggerOkHook(mParticles, mReadEventCounter); + break; + } else { + mTriggerFalseHook(mParticles, mReadEventCounter); + } } - /** trigger event **/ - if (triggerEvent()) { - mTriggerOkHook(mParticles, mReadEventCounter); - break; - } else { - mTriggerFalseHook(mParticles, mReadEventCounter); + /** add tracks **/ + if (!addTracks(primGen)) { + LOG(error) << "ReadEvent failed in addTracks"; + return kFALSE; } - } - /** add tracks **/ - if (!addTracks(primGen)) { - LOG(error) << "ReadEvent failed in addTracks"; - return kFALSE; - } + /** update header **/ + auto header = primGen->GetEvent(); + auto o2header = dynamic_cast(header); + if (!header) { + LOG(fatal) << "MC event header is not a 'o2::dataformats::MCEventHeader' object"; + return kFALSE; + } + updateHeader(o2header); + updateSubGeneratorInformation(o2header); - /** update header **/ - auto header = primGen->GetEvent(); - auto o2header = dynamic_cast(header); - if (!header) { - LOG(fatal) << "MC event header is not a 'o2::dataformats::MCEventHeader' object"; - return kFALSE; + /** success **/ + return kTRUE; } - updateHeader(o2header); - updateSubGeneratorInformation(o2header); - /** success **/ - return kTRUE; -} + /*****************************************************************/ -/*****************************************************************/ + Bool_t + Generator::addTracks(FairPrimaryGenerator * primGen) + { + /** add tracks **/ -Bool_t - Generator::addTracks(FairPrimaryGenerator* primGen) -{ - /** add tracks **/ + auto o2primGen = dynamic_cast(primGen); + if (!o2primGen) { + LOG(fatal) << "PrimaryGenerator is not a o2::eventgen::PrimaryGenerator"; + return kFALSE; + } - auto o2primGen = dynamic_cast(primGen); - if (!o2primGen) { - LOG(fatal) << "PrimaryGenerator is not a o2::eventgen::PrimaryGenerator"; - return kFALSE; - } + /** loop over particles **/ + for (const auto& particle : mParticles) { + o2primGen->AddTrack(particle.GetPdgCode(), + particle.Px() * mMomentumUnit, + particle.Py() * mMomentumUnit, + particle.Pz() * mMomentumUnit, + particle.Vx() * mPositionUnit, + particle.Vy() * mPositionUnit, + particle.Vz() * mPositionUnit, + particle.GetMother(0), + particle.GetMother(1), + particle.GetDaughter(0), + particle.GetDaughter(1), + particle.TestBit(ParticleStatus::kToBeDone), + particle.Energy() * mEnergyUnit, + particle.T() * mTimeUnit, + particle.GetWeight(), + (TMCProcess)particle.GetUniqueID(), + particle.GetStatusCode()); // generator status information passed as status code field + } - /** loop over particles **/ - for (const auto& particle : mParticles) { - o2primGen->AddTrack(particle.GetPdgCode(), - particle.Px() * mMomentumUnit, - particle.Py() * mMomentumUnit, - particle.Pz() * mMomentumUnit, - particle.Vx() * mPositionUnit, - particle.Vy() * mPositionUnit, - particle.Vz() * mPositionUnit, - particle.GetMother(0), - particle.GetMother(1), - particle.GetDaughter(0), - particle.GetDaughter(1), - particle.TestBit(ParticleStatus::kToBeDone), - particle.Energy() * mEnergyUnit, - particle.T() * mTimeUnit, - particle.GetWeight(), - (TMCProcess)particle.GetUniqueID(), - particle.GetStatusCode()); // generator status information passed as status code field + /** success **/ + return kTRUE; } - /** success **/ - return kTRUE; -} - -/*****************************************************************/ + /*****************************************************************/ -Bool_t - Generator::boostEvent() -{ - /** boost event **/ - - /** success **/ - return kTRUE; -} - -/*****************************************************************/ - -Bool_t - Generator::triggerEvent() -{ - /** trigger event **/ + Bool_t + Generator::boostEvent() + { + /** boost event **/ - /** check trigger presence **/ - if (mTriggers.size() == 0 && mDeepTriggers.size() == 0) { + /** success **/ return kTRUE; } - /** check trigger mode **/ - Bool_t triggered; - if (mTriggerMode == kTriggerOFF) { - return kTRUE; - } else if (mTriggerMode == kTriggerOR) { - triggered = kFALSE; - } else if (mTriggerMode == kTriggerAND) { - triggered = kTRUE; - } else { - return kTRUE; - } + /*****************************************************************/ - /** loop over triggers **/ - for (const auto& trigger : mTriggers) { - auto retval = trigger(mParticles); - if (mTriggerMode == kTriggerOR) { - triggered |= retval; + Bool_t + Generator::triggerEvent() + { + /** trigger event **/ + + /** check trigger presence **/ + if (mTriggers.size() == 0 && mDeepTriggers.size() == 0) { + return kTRUE; } - if (mTriggerMode == kTriggerAND) { - triggered &= retval; + + /** check trigger mode **/ + Bool_t triggered; + if (mTriggerMode == kTriggerOFF) { + return kTRUE; + } else if (mTriggerMode == kTriggerOR) { + triggered = kFALSE; + } else if (mTriggerMode == kTriggerAND) { + triggered = kTRUE; + } else { + return kTRUE; } - } - /** loop over deep triggers **/ - for (const auto& trigger : mDeepTriggers) { - auto retval = trigger(mInterface, mInterfaceName); - if (mTriggerMode == kTriggerOR) { - triggered |= retval; + /** loop over triggers **/ + for (const auto& trigger : mTriggers) { + auto retval = trigger(mParticles); + if (mTriggerMode == kTriggerOR) { + triggered |= retval; + } + if (mTriggerMode == kTriggerAND) { + triggered &= retval; + } } - if (mTriggerMode == kTriggerAND) { - triggered &= retval; + + /** loop over deep triggers **/ + for (const auto& trigger : mDeepTriggers) { + auto retval = trigger(mInterface, mInterfaceName); + if (mTriggerMode == kTriggerOR) { + triggered |= retval; + } + if (mTriggerMode == kTriggerAND) { + triggered &= retval; + } } - } - /** return **/ - return triggered; -} + /** return **/ + return triggered; + } -/*****************************************************************/ + /*****************************************************************/ -void Generator::addSubGenerator(int subGeneratorId, std::string const& subGeneratorDescription) -{ - if (subGeneratorId < 0) { - LOG(fatal) << "Sub-generator IDs must be >= 0, instead, passed value is " << subGeneratorId; + void Generator::addSubGenerator(int subGeneratorId, std::string const& subGeneratorDescription) + { + if (subGeneratorId < 0) { + LOG(fatal) << "Sub-generator IDs must be >= 0, instead, passed value is " << subGeneratorId; + } + mSubGeneratorsIdToDesc.insert({subGeneratorId, subGeneratorDescription}); } - mSubGeneratorsIdToDesc.insert({subGeneratorId, subGeneratorDescription}); -} -/*****************************************************************/ + /*****************************************************************/ -void Generator::updateSubGeneratorInformation(o2::dataformats::MCEventHeader* header) const -{ - if (mSubGeneratorId < 0) { - return; + void Generator::updateSubGeneratorInformation(o2::dataformats::MCEventHeader * header) const + { + if (mSubGeneratorId < 0) { + return; + } + header->putInfo(o2::mcgenid::GeneratorProperty::SUBGENERATORID, mSubGeneratorId); + header->putInfo>(o2::mcgenid::GeneratorProperty::SUBGENERATORDESCRIPTIONMAP, mSubGeneratorsIdToDesc); } - header->putInfo(o2::mcgenid::GeneratorProperty::SUBGENERATORID, mSubGeneratorId); - header->putInfo>(o2::mcgenid::GeneratorProperty::SUBGENERATORDESCRIPTIONMAP, mSubGeneratorsIdToDesc); -} -/*****************************************************************/ -/*****************************************************************/ + /*****************************************************************/ + /*****************************************************************/ } /* namespace eventgen */ } /* namespace o2 */ diff --git a/Generators/src/GeneratorsLinkDef.h b/Generators/src/GeneratorsLinkDef.h index 24b3f2e452498..97896d8225042 100644 --- a/Generators/src/GeneratorsLinkDef.h +++ b/Generators/src/GeneratorsLinkDef.h @@ -35,7 +35,7 @@ #pragma link C++ class o2::eventgen::GeneratorFromEventPool + ; #pragma link C++ class o2::eventgen::GeneratorEventPoolParam + ; #pragma link C++ class o2::eventgen::EventPoolGenConfig + ; -#ifdef GENERATORS_WITH_TPCLOOPERS +#ifdef GENERATORS_WITH_ONNXRUNTIME #pragma link C++ class o2::eventgen::GenTPCLoopers + ; #pragma link C++ class o2::eventgen::GenTPCLoopersParam + ; #endif diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx index 109461ab71dfa..4eacb7674599c 100644 --- a/Generators/src/TPCLoopers.cxx +++ b/Generators/src/TPCLoopers.cxx @@ -382,6 +382,9 @@ void GenTPCLoopers::setFlatGas(Bool_t& flat, const Int_t& number) if (mInteractionTimeRecords.empty()) { LOG(error) << "Error: No interaction time records found in the collision context!"; exit(1); + } else { + LOG(info) << "Interaction Time records has " << mInteractionTimeRecords.size() << " entries."; + mCollisionContext->printCollisionSummary(); } for (int c = 0; c < mInteractionTimeRecords.size() - 1; c++) { mIntTimeRecMean += mInteractionTimeRecords[c + 1].bc2ns() - mInteractionTimeRecords[c].bc2ns(); From 707f03c2236c902b0042dd523ab0fde29445be06 Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Mon, 5 Jan 2026 10:21:41 +0100 Subject: [PATCH 052/234] Revert "First implementation of loopers inclusion in base Generator class" This reverts commit b8c867dbb27d08e9ecf3134aeb72886fbb3c878c. --- .../SimConfig/include/SimConfig/SimConfig.h | 3 - Common/SimConfig/src/SimConfig.cxx | 2 - Generators/CMakeLists.txt | 13 - Generators/include/Generators/Generator.h | 13 - .../include/Generators/TPCLoopersParam.h | 48 -- Generators/include/TPCLoopers.h | 127 ----- .../share/egconfig/ScalerComptonParams.json | 28 -- .../share/egconfig/ScalerPairParams.json | 34 -- Generators/share/egconfig/gaussian_params.csv | 4 - Generators/share/egconfig/poisson_params.csv | 3 - Generators/src/Generator.cxx | 442 ++++++------------ Generators/src/GeneratorsLinkDef.h | 4 - Generators/src/TPCLoopers.cxx | 417 ----------------- Generators/src/TPCLoopersParam.cxx | 15 - 14 files changed, 146 insertions(+), 1007 deletions(-) delete mode 100644 Generators/include/Generators/TPCLoopersParam.h delete mode 100644 Generators/include/TPCLoopers.h delete mode 100644 Generators/share/egconfig/ScalerComptonParams.json delete mode 100644 Generators/share/egconfig/ScalerPairParams.json delete mode 100644 Generators/share/egconfig/gaussian_params.csv delete mode 100644 Generators/share/egconfig/poisson_params.csv delete mode 100644 Generators/src/TPCLoopers.cxx delete mode 100644 Generators/src/TPCLoopersParam.cxx diff --git a/Common/SimConfig/include/SimConfig/SimConfig.h b/Common/SimConfig/include/SimConfig/SimConfig.h index 8642a0e5bc225..be88d9fbd8c33 100644 --- a/Common/SimConfig/include/SimConfig/SimConfig.h +++ b/Common/SimConfig/include/SimConfig/SimConfig.h @@ -52,7 +52,6 @@ struct SimConfigData { std::vector mActiveModules; // list of active modules std::vector mReadoutDetectors; // list of readout detectors std::string mMCEngine; // chosen VMC engine - bool mNoLoopers = false; // Disable automatic TPC loopers std::string mGenerator; // chosen VMC generator std::string mTrigger; // chosen VMC generator trigger unsigned int mNEvents; // number of events to be simulated @@ -139,8 +138,6 @@ class SimConfig // get selected active detectors std::vector const& getActiveModules() const { return mConfigData.mActiveModules; } std::vector const& getReadoutDetectors() const { return mConfigData.mReadoutDetectors; } - // get loopers veto - bool getLoopersVeto() const { return mConfigData.mNoLoopers; } // static helper functions to determine list of active / readout modules // can also be used from outside diff --git a/Common/SimConfig/src/SimConfig.cxx b/Common/SimConfig/src/SimConfig.cxx index 5ddc3199e3d4a..15879687872d5 100644 --- a/Common/SimConfig/src/SimConfig.cxx +++ b/Common/SimConfig/src/SimConfig.cxx @@ -74,7 +74,6 @@ void SimConfig::initOptions(boost::program_options::options_description& options "run", bpo::value()->default_value(-1), "ALICE run number")( "asservice", bpo::value()->default_value(false), "run in service/server mode")( "noGeant", bpo::bool_switch(), "prohibits any Geant transport/physics (by using tight cuts)")( - "noLoopers", bpo::bool_switch(), "disable automatic TPC loopers")( "forwardKine", bpo::bool_switch(), "forward kinematics on a FairMQ channel")( "noDiscOutput", bpo::bool_switch(), "switch off writing sim results to disc (useful in combination with forwardKine)"); options.add_options()("fromCollContext", bpo::value()->default_value(""), "Use a pregenerated collision context to infer number of events to simulate, how to embedd them, the vertex position etc. Takes precedence of other options such as \"--nEvents\". The format is COLLISIONCONTEXTFILE.root[:SIGNALNAME] where SIGNALNAME is the event part in the context which is relevant."); @@ -298,7 +297,6 @@ bool SimConfig::resetFromParsedMap(boost::program_options::variables_map const& using o2::detectors::DetID; mConfigData.mMCEngine = vm["mcEngine"].as(); mConfigData.mNoGeant = vm["noGeant"].as(); - mConfigData.mNoLoopers = vm["noLoopers"].as(); // Reset modules and detectors as they are anyway re-parsed mConfigData.mReadoutDetectors.clear(); diff --git a/Generators/CMakeLists.txt b/Generators/CMakeLists.txt index 56fe8b8fc2284..02caa63df0d43 100644 --- a/Generators/CMakeLists.txt +++ b/Generators/CMakeLists.txt @@ -41,8 +41,6 @@ o2_add_library(Generators src/GeneratorTParticleParam.cxx src/GeneratorService.cxx src/FlowMapper.cxx - $<$:src/TPCLoopers.cxx> - $<$:src/TPCLoopersParam.cxx> $<$:src/GeneratorPythia8.cxx> $<$:src/DecayerPythia8.cxx> $<$:src/GeneratorPythia8Param.cxx> @@ -55,7 +53,6 @@ o2_add_library(Generators PUBLIC_LINK_LIBRARIES FairRoot::Base O2::SimConfig O2::CommonUtils O2::DetectorsBase O2::ZDCBase O2::SimulationDataFormat ${pythiaTarget} ${hepmcTarget} FairRoot::Gen - $<$:onnxruntime::onnxruntime> TARGETVARNAME targetName) if(pythia_FOUND) @@ -66,10 +63,6 @@ if(HepMC3_FOUND) target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_HEPMC3) endif() -if(onnxruntime_FOUND) - target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_ONNXRUNTIME) -endif() - set(headers include/Generators/Generator.h include/Generators/Trigger.h @@ -95,12 +88,6 @@ set(headers include/Generators/FlowMapper.h ) -if(onnxruntime_FOUND) - list(APPEND headers - include/Generators/TPCLoopers.h - include/Generators/TPCLoopersParam.h) -endif() - if(pythia_FOUND) list(APPEND headers include/Generators/GeneratorPythia8.h diff --git a/Generators/include/Generators/Generator.h b/Generators/include/Generators/Generator.h index 374d53f324399..bd35a00793e2d 100644 --- a/Generators/include/Generators/Generator.h +++ b/Generators/include/Generators/Generator.h @@ -17,10 +17,6 @@ #include "FairGenerator.h" #include "TParticle.h" #include "Generators/Trigger.h" -#ifdef GENERATORS_WITH_ONNXRUNTIME -#include "Generators/TPCLoopers.h" -#include "Generators/TPCLoopersParam.h" -#endif #include #include #include @@ -77,7 +73,6 @@ class Generator : public FairGenerator /** methods to override **/ virtual Bool_t generateEvent() = 0; // generates event (in structure internal to generator) virtual Bool_t importParticles() = 0; // fills the mParticles vector (transfer from generator state) - Bool_t loopers(); // adds loopers to the event in case TPC is used virtual void updateHeader(o2::dataformats::MCEventHeader* eventHeader) {}; Bool_t triggerEvent(); @@ -159,8 +154,6 @@ class Generator : public FairGenerator private: void updateSubGeneratorInformation(o2::dataformats::MCEventHeader* header) const; - // loopers flag - Bool_t mAddLoopers = kFALSE; // collect an ID and a short description of sub-generator entities std::unordered_map mSubGeneratorsIdToDesc; // the current ID of the sub-generator used in the current event (if applicable) @@ -169,12 +162,6 @@ class Generator : public FairGenerator // global static information about (upper limit of) number of events to be generated static unsigned int gTotalNEvents; -#ifdef GENERATORS_WITH_ONNXRUNTIME - // Loopers generator instance - std::unique_ptr mLoopersGen = nullptr; -#endif - void initLoopersGen(); - ClassDefOverride(Generator, 2); }; /** class Generator **/ diff --git a/Generators/include/Generators/TPCLoopersParam.h b/Generators/include/Generators/TPCLoopersParam.h deleted file mode 100644 index ceeea201538b2..0000000000000 --- a/Generators/include/Generators/TPCLoopersParam.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2024-2025 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \author M+Giacalone - September 2025 - -#ifndef ALICEO2_EVENTGEN_TPCLOOPERSPARAM_H_ -#define ALICEO2_EVENTGEN_TPCLOOPERSPARAM_H_ - -#include "CommonUtils/ConfigurableParam.h" -#include "CommonUtils/ConfigurableParamHelper.h" - -namespace o2 -{ -namespace eventgen -{ - -/** - ** a parameter class/struct to keep the settings of - ** the tpc loopers event-generator and - ** allow the user to modify them - **/ -struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper { - std::string model_pairs = "ccdb://Users/m/mgiacalo/WGAN_ExtGenPair"; // ONNX model for e+e- pair production - std::string model_compton = "ccdb://Users/m/mgiacalo/WGAN_ExtGenCompton"; // ONNX model for Compton scattering - std::string poisson = "${O2_ROOT}/share/Generators/egconfig/poisson_params.csv"; // file with Poissonian parameters - std::string gauss = "${O2_ROOT}/share/Generators/egconfig/gaussian_params.csv"; // file with Gaussian parameters - std::string scaler_pair = "${O2_ROOT}/share/Generators/egconfig/ScalerPairParams.json"; // file with scaler parameters for e+e- pair production - std::string scaler_compton = "${O2_ROOT}/share/Generators/egconfig/ScalerComptonParams.json"; // file with scaler parameters for Compton scattering - bool flat_gas = true; // if true, the gas density is considered flat in the TPC volume - int nFlatGasLoopers = 500; // number of loopers to be generated per event in case of flat gas - float fraction_pairs = 0.08; // fraction of loopers - std::array multiplier = {1., 1.}; // multiplier for pairs and compton loopers for Poissonian and Gaussian sampling - std::array fixedNLoopers = {1, 1}; // fixed number of loopers coming from pairs and compton electrons - valid if flat gas is false and both Poisson and Gaussian params files are empty - O2ParamDef(GenTPCLoopersParam, "GenTPCLoopers"); -}; - -} // end namespace eventgen -} // end namespace o2 - -#endif // ALICEO2_EVENTGEN_TPCLOOPERSPARAM_H_ diff --git a/Generators/include/TPCLoopers.h b/Generators/include/TPCLoopers.h deleted file mode 100644 index 70146a82baf60..0000000000000 --- a/Generators/include/TPCLoopers.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef ALICEO2_EVENTGEN_TPCLOOPERS_H_ -#define ALICEO2_EVENTGEN_TPCLOOPERS_H_ - -#ifdef GENERATORS_WITH_ONNXRUNTIME -#include -#endif -#include -#include -#include -#include -#include "CCDB/CCDBTimeStampUtils.h" -#include "CCDB/CcdbApi.h" -#include "DetectorsRaw/HBFUtils.h" -#include "TRandom3.h" -#include "TDatabasePDG.h" -#include -#include -#include "SimulationDataFormat/MCGenProperties.h" -#include "TParticle.h" -#include - -#ifdef GENERATORS_WITH_ONNXRUNTIME -// Static Ort::Env instance for multiple onnx model loading -extern Ort::Env global_env; -#endif - -#ifdef GENERATORS_WITH_ONNXRUNTIME -// This class is responsible for loading the scaler parameters from a JSON file -// and applying the inverse transformation to the generated data. -struct Scaler -{ - std::vector normal_min; - std::vector normal_max; - std::vector outlier_center; - std::vector outlier_scale; - - void load(const std::string &filename); - - std::vector inverse_transform(const std::vector &input); - -private: - std::vector jsonArrayToVector(const rapidjson::Value &jsonArray); -}; - -// This class loads the ONNX model and generates samples using it. -class ONNXGenerator -{ -public: - ONNXGenerator(Ort::Env &shared_env, const std::string &model_path); - - std::vector generate_sample(); - -private: - Ort::Env &env; - Ort::Session session; - TRandom3 rand_gen; -}; -#endif // GENERATORS_WITH_ONNXRUNTIME - -namespace o2 -{ -namespace eventgen -{ - -#ifdef GENERATORS_WITH_ONNXRUNTIME -class GenTPCLoopers -{ - public: - GenTPCLoopers(std::string model_pairs = "tpcloopmodel.onnx", std::string model_compton = "tpcloopmodelcompton.onnx", - std::string poisson = "poisson.csv", std::string gauss = "gauss.csv", std::string scaler_pair = "scaler_pair.json", - std::string scaler_compton = "scaler_compton.json"); - - Bool_t generateEvent(); - - Bool_t generateEvent(double &time_limit); - - std::vector importParticles(); - - unsigned int PoissonPairs(); - - unsigned int GaussianElectrons(); - - void SetNLoopers(unsigned int &nsig_pair, unsigned int &nsig_compton); - - void SetMultiplier(std::array &mult); - - void setFlatGas(Bool_t &flat, const Int_t &number = -1); - - void setFractionPairs(float &fractionPairs); - - private: - std::unique_ptr mONNX_pair = nullptr; - std::unique_ptr mONNX_compton = nullptr; - std::unique_ptr mScaler_pair = nullptr; - std::unique_ptr mScaler_compton = nullptr; - double mPoisson[3] = {0.0, 0.0, 0.0}; // Mu, Min and Max of Poissonian - double mGauss[4] = {0.0, 0.0, 0.0, 0.0}; // Mean, Std, Min, Max - std::vector> mGenPairs; - std::vector> mGenElectrons; - unsigned int mNLoopersPairs = -1; - unsigned int mNLoopersCompton = -1; - std::array mMultiplier = {1., 1.}; - bool mPoissonSet = false; - bool mGaussSet = false; - // Random number generator - TRandom3 mRandGen; - // Masses of the electrons and positrons - TDatabasePDG *mPDG = TDatabasePDG::Instance(); - double mMass_e = mPDG->GetParticle(11)->Mass(); - double mMass_p = mPDG->GetParticle(-11)->Mass(); - int mCurrentEvent = 0; // Current event number, used for adaptive loopers - TFile *mContextFile = nullptr; // Input collision context file - o2::steer::DigitizationContext *mCollisionContext = nullptr; // Pointer to the digitization context - std::vector mInteractionTimeRecords; // Interaction time records from collision context - Bool_t mFlatGas = false; // Flag to indicate if flat gas loopers are used - Int_t mFlatGasNumber = -1; // Number of flat gas loopers per event - double mIntTimeRecMean = 1.0; // Average interaction time record used for the reference - double mTimeLimit = 0.0; // Time limit for the current event - double mTimeEnd = 0.0; // Time limit for the last event - float mLoopsFractionPairs = 0.08; // Fraction of loopers from Pairs -}; -#endif // GENERATORS_WITH_ONNXRUNTIME - -} // namespace eventgen -} // namespace o2 - -#endif // ALICEO2_EVENTGEN_TPCLOOPERS_H_ \ No newline at end of file diff --git a/Generators/share/egconfig/ScalerComptonParams.json b/Generators/share/egconfig/ScalerComptonParams.json deleted file mode 100644 index d8e654847f46e..0000000000000 --- a/Generators/share/egconfig/ScalerComptonParams.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "normal": { - "min": [ - -0.0108811147511005, - -0.0098758740350604, - -0.0103233363479375, - -260.0542297363281, - -259.80059814453125 - ], - "max": [ - 0.0108060473576188, - 0.0103057539090514, - 0.0106524610891938, - 260.0343933105469, - 259.62890625 - ] - }, - "outlier": { - "center": [ - -71.39387130737305, - 96791.23828125 - ], - "scale": [ - 265.9389114379883, - 230762.30981445312 - ] - } -} \ No newline at end of file diff --git a/Generators/share/egconfig/ScalerPairParams.json b/Generators/share/egconfig/ScalerPairParams.json deleted file mode 100644 index 61434bfa2462e..0000000000000 --- a/Generators/share/egconfig/ScalerPairParams.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "normal": { - "min": [ - -0.0073022879660129, - -0.0077305701561272, - -0.0076750442385673, - -0.0082916170358657, - -0.0079681202769279, - -0.0077468422241508, - -255.6164093017578, - -252.9441680908203 - ], - "max": [ - 0.007688719779253, - 0.0077241472899913, - 0.0075828479602932, - 0.00813714787364, - 0.0083825681358575, - 0.0073839174583554, - 256.2904968261719, - 253.4925842285156 - ] - }, - "outlier": { - "center": [ - -79.66580963134766, - 141535.640625 - ], - "scale": [ - 250.8921127319336, - 222363.16015625 - ] - } -} \ No newline at end of file diff --git a/Generators/share/egconfig/gaussian_params.csv b/Generators/share/egconfig/gaussian_params.csv deleted file mode 100644 index 8e07c22dd30bf..0000000000000 --- a/Generators/share/egconfig/gaussian_params.csv +++ /dev/null @@ -1,4 +0,0 @@ -9.611554230339172022e+01 -1.963570744941765867e+01 -4.300000000000000000e+01 -1.690000000000000000e+02 diff --git a/Generators/share/egconfig/poisson_params.csv b/Generators/share/egconfig/poisson_params.csv deleted file mode 100644 index ef26bd973d34c..0000000000000 --- a/Generators/share/egconfig/poisson_params.csv +++ /dev/null @@ -1,3 +0,0 @@ -3.165383056343737511e+00 -1.000000000000000000e+00 -1.200000000000000000e+01 diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 153ef5cd5e35e..9204ede98215e 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -17,14 +17,11 @@ #include "SimulationDataFormat/MCEventHeader.h" #include "SimulationDataFormat/ParticleStatus.h" #include "SimulationDataFormat/MCGenProperties.h" -#include #include "FairPrimaryGenerator.h" #include #include #include "TClonesArray.h" #include "TParticle.h" -#include "TSystem.h" -#include "TGrid.h" namespace o2 { @@ -42,18 +39,6 @@ Generator::Generator() : FairGenerator("ALICEo2", "ALICEo2 Generator"), /** default constructor **/ mThisInstanceID = Generator::InstanceCounter; Generator::InstanceCounter++; - auto simConfig = o2::conf::SimConfig::Instance(); - auto noLoops = simConfig.getLoopersVeto(); - if (!noLoops) { - bool transport = (simConfig.getMCEngine() != "O2TrivialMCEngine"); - if (transport) { - bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); - if (tpcActive) { - mAddLoopers = kTRUE; - initLoopersGen(); - } - } - } } /*****************************************************************/ @@ -64,102 +49,6 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na /** constructor **/ mThisInstanceID = Generator::InstanceCounter; Generator::InstanceCounter++; - auto simConfig = o2::conf::SimConfig::Instance(); - auto noLoops = simConfig.getLoopersVeto(); - if (!noLoops) { - bool transport = (simConfig.getMCEngine() != "O2TrivialMCEngine"); - if (transport) { - bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); - if (tpcActive) { - mAddLoopers = kTRUE; - initLoopersGen(); - } - } - } -} - -/*****************************************************************/ - -void Generator::initLoopersGen() -{ -#ifdef GENERATORS_WITH_ONNXRUNTIME - // Expand all environment paths - const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); - std::string model_pairs = gSystem->ExpandPathName(loopersParam.model_pairs.c_str()); - std::string model_compton = gSystem->ExpandPathName(loopersParam.model_compton.c_str()); - const auto& scaler_pair = gSystem->ExpandPathName(loopersParam.scaler_pair.c_str()); - const auto& scaler_compton = gSystem->ExpandPathName(loopersParam.scaler_compton.c_str()); - const auto& poisson = gSystem->ExpandPathName(loopersParam.poisson.c_str()); - const auto& gauss = gSystem->ExpandPathName(loopersParam.gauss.c_str()); - auto flat_gas = loopersParam.flat_gas; - const auto& nFlatGasLoopers = loopersParam.nFlatGasLoopers; - auto fraction_pairs = loopersParam.fraction_pairs; - auto multiplier = loopersParam.multiplier; - auto fixedNLoopers = loopersParam.fixedNLoopers; - const std::array models = {model_pairs, model_compton}; - const std::array local_names = {"WGANpair.onnx", "WGANcompton.onnx"}; - const std::array isAlien = {models[0].starts_with("alien://"), models[1].starts_with("alien://")}; - const std::array isCCDB = {models[0].starts_with("ccdb://"), models[1].starts_with("ccdb://")}; - if (std::any_of(isAlien.begin(), isAlien.end(), [](bool v) { return v; })) { - if (!gGrid) { - TGrid::Connect("alien://"); - if (!gGrid) { - LOG(fatal) << "AliEn connection failed, check token."; - exit(1); - } - } - for (size_t i = 0; i < models.size(); ++i) { - if (isAlien[i] && !TFile::Cp(models[i].c_str(), local_names[i].c_str())) { - LOG(fatal) << "Error: Model file " << models[i] << " does not exist!"; - exit(1); - } - } - } - if (std::any_of(isCCDB.begin(), isCCDB.end(), [](bool v) { return v; })) { - o2::ccdb::CcdbApi ccdb_api; - ccdb_api.init("http://alice-ccdb.cern.ch"); - for (size_t i = 0; i < models.size(); ++i) { - if (isCCDB[i]) { - auto model_path = models[i].substr(7); // Remove "ccdb://" - // Treat filename if provided in the CCDB path - auto extension = model_path.find(".onnx"); - if (extension != std::string::npos) { - auto last_slash = model_path.find_last_of('/'); - model_path = model_path.substr(0, last_slash); - } - std::map filter; - if (!ccdb_api.retrieveBlob(model_path, "./", filter, o2::ccdb::getCurrentTimestamp(), false, local_names[i].c_str())) { - LOG(fatal) << "Error: issues in retrieving " << model_path << " from CCDB!"; - exit(1); - } - } - } - } - model_pairs = isAlien[0] || isCCDB[0] ? local_names[0] : model_pairs; - model_compton = isAlien[1] || isCCDB[1] ? local_names[1] : model_compton; - try { - // Create the TPC loopers generator with the provided parameters - mLoopersGen = std::make_unique(model_pairs, model_compton, poisson, gauss, scaler_pair, scaler_compton); - - // Configure the generator with flat gas loopers if enabled (default) - if (flat_gas) { - mLoopersGen->setFlatGas(flat_gas, nFlatGasLoopers); - mLoopersGen->setFractionPairs(fraction_pairs); - } else { - // Otherwise, Poisson+Gauss sampling or fixed number of loopers will be used - // Multiplier is applied only with distribution sampling - // This configuration can be used for testing purposes, in all other cases flat gas is recommended - mLoopersGen->SetNLoopers(fixedNLoopers[0], fixedNLoopers[1]); - mLoopersGen->SetMultiplier(multiplier); - } - LOG(info) << "TPC Loopers generator initialized successfully"; - } catch (const std::exception& e) { - LOG(error) << "Failed to initialize TPC Loopers generator: " << e.what(); - mLoopersGen.reset(); - } -#else - LOG(warn) << "ONNX Runtime support not available, cannot initialize TPC loopers generator"; -#endif } /*****************************************************************/ @@ -176,230 +65,191 @@ Bool_t /*****************************************************************/ Bool_t - Generator::loopers() + Generator::ReadEvent(FairPrimaryGenerator* primGen) { -#ifdef GENERATORS_WITH_ONNXRUNTIME - if (!mLoopersGen) { - LOG(error) << "Loopers generator not initialized"; - return kFALSE; + /** read event **/ + + /** endless generate-and-trigger loop **/ + while (true) { + mReadEventCounter++; + + /** clear particle vector **/ + mParticles.clear(); + + /** reset the sub-generator ID **/ + mSubGeneratorId = -1; + + /** generate event **/ + if (!generateEvent()) { + LOG(error) << "ReadEvent failed in generateEvent"; + return kFALSE; + } + + /** import particles **/ + if (!importParticles()) { + LOG(error) << "ReadEvent failed in importParticles"; + return kFALSE; + } + + if (mSubGeneratorsIdToDesc.empty() && mSubGeneratorId > -1) { + LOG(fatal) << "ReadEvent failed because no SubGenerator description given"; + } + + if (!mSubGeneratorsIdToDesc.empty() && mSubGeneratorId < 0) { + LOG(fatal) << "ReadEvent failed because SubGenerator description given but sub-generator not set"; + } + + /** trigger event **/ + if (triggerEvent()) { + mTriggerOkHook(mParticles, mReadEventCounter); + break; + } else { + mTriggerFalseHook(mParticles, mReadEventCounter); + } } - // Generate loopers using the initialized TPC loopers generator - if (!mLoopersGen->generateEvent()) { - LOG(error) << "Failed to generate loopers event"; + /** add tracks **/ + if (!addTracks(primGen)) { + LOG(error) << "ReadEvent failed in addTracks"; return kFALSE; } - const auto& looperParticles = mLoopersGen->importParticles(); - if (looperParticles.empty()) { - LOG(error) << "Failed to import loopers particles"; + + /** update header **/ + auto header = primGen->GetEvent(); + auto o2header = dynamic_cast(header); + if (!header) { + LOG(fatal) << "MC event header is not a 'o2::dataformats::MCEventHeader' object"; return kFALSE; } - // Append the generated looper particles to the main particle list - mParticles.insert(mParticles.end(), looperParticles.begin(), looperParticles.end()); + updateHeader(o2header); + updateSubGeneratorInformation(o2header); - LOG(debug) << "Added " << looperParticles.size() << " looper particles"; - return kTRUE; -#else - LOG(warn) << "ONNX Runtime support not available, skipping TPC loopers generation"; + /** success **/ return kTRUE; -#endif } - /*****************************************************************/ - - Bool_t - Generator::ReadEvent(FairPrimaryGenerator * primGen) - { - /** read event **/ - - /** endless generate-and-trigger loop **/ - while (true) { - mReadEventCounter++; - - /** clear particle vector **/ - mParticles.clear(); - - /** reset the sub-generator ID **/ - mSubGeneratorId = -1; - - /** generate event **/ - if (!generateEvent()) { - LOG(error) << "ReadEvent failed in generateEvent"; - return kFALSE; - } - - /** import particles **/ - if (!importParticles()) { - LOG(error) << "ReadEvent failed in importParticles"; - return kFALSE; - } - - /** Add loopers **/ - if(mAddLoopers){ - if (!loopers()) { - LOG(error) << "ReadEvent failed in loopers"; - return kFALSE; - } - } - - if (mSubGeneratorsIdToDesc.empty() && mSubGeneratorId > -1) { - LOG(fatal) << "ReadEvent failed because no SubGenerator description given"; - } - - if (!mSubGeneratorsIdToDesc.empty() && mSubGeneratorId < 0) { - LOG(fatal) << "ReadEvent failed because SubGenerator description given but sub-generator not set"; - } - - /** trigger event **/ - if (triggerEvent()) { - mTriggerOkHook(mParticles, mReadEventCounter); - break; - } else { - mTriggerFalseHook(mParticles, mReadEventCounter); - } - } - /** add tracks **/ - if (!addTracks(primGen)) { - LOG(error) << "ReadEvent failed in addTracks"; - return kFALSE; - } +/*****************************************************************/ - /** update header **/ - auto header = primGen->GetEvent(); - auto o2header = dynamic_cast(header); - if (!header) { - LOG(fatal) << "MC event header is not a 'o2::dataformats::MCEventHeader' object"; - return kFALSE; - } - updateHeader(o2header); - updateSubGeneratorInformation(o2header); +Bool_t + Generator::addTracks(FairPrimaryGenerator* primGen) +{ + /** add tracks **/ - /** success **/ - return kTRUE; + auto o2primGen = dynamic_cast(primGen); + if (!o2primGen) { + LOG(fatal) << "PrimaryGenerator is not a o2::eventgen::PrimaryGenerator"; + return kFALSE; } - /*****************************************************************/ + /** loop over particles **/ + for (const auto& particle : mParticles) { + o2primGen->AddTrack(particle.GetPdgCode(), + particle.Px() * mMomentumUnit, + particle.Py() * mMomentumUnit, + particle.Pz() * mMomentumUnit, + particle.Vx() * mPositionUnit, + particle.Vy() * mPositionUnit, + particle.Vz() * mPositionUnit, + particle.GetMother(0), + particle.GetMother(1), + particle.GetDaughter(0), + particle.GetDaughter(1), + particle.TestBit(ParticleStatus::kToBeDone), + particle.Energy() * mEnergyUnit, + particle.T() * mTimeUnit, + particle.GetWeight(), + (TMCProcess)particle.GetUniqueID(), + particle.GetStatusCode()); // generator status information passed as status code field + } - Bool_t - Generator::addTracks(FairPrimaryGenerator * primGen) - { - /** add tracks **/ + /** success **/ + return kTRUE; +} - auto o2primGen = dynamic_cast(primGen); - if (!o2primGen) { - LOG(fatal) << "PrimaryGenerator is not a o2::eventgen::PrimaryGenerator"; - return kFALSE; - } +/*****************************************************************/ - /** loop over particles **/ - for (const auto& particle : mParticles) { - o2primGen->AddTrack(particle.GetPdgCode(), - particle.Px() * mMomentumUnit, - particle.Py() * mMomentumUnit, - particle.Pz() * mMomentumUnit, - particle.Vx() * mPositionUnit, - particle.Vy() * mPositionUnit, - particle.Vz() * mPositionUnit, - particle.GetMother(0), - particle.GetMother(1), - particle.GetDaughter(0), - particle.GetDaughter(1), - particle.TestBit(ParticleStatus::kToBeDone), - particle.Energy() * mEnergyUnit, - particle.T() * mTimeUnit, - particle.GetWeight(), - (TMCProcess)particle.GetUniqueID(), - particle.GetStatusCode()); // generator status information passed as status code field - } +Bool_t + Generator::boostEvent() +{ + /** boost event **/ - /** success **/ - return kTRUE; - } + /** success **/ + return kTRUE; +} - /*****************************************************************/ +/*****************************************************************/ - Bool_t - Generator::boostEvent() - { - /** boost event **/ +Bool_t + Generator::triggerEvent() +{ + /** trigger event **/ - /** success **/ + /** check trigger presence **/ + if (mTriggers.size() == 0 && mDeepTriggers.size() == 0) { return kTRUE; } - /*****************************************************************/ - - Bool_t - Generator::triggerEvent() - { - /** trigger event **/ + /** check trigger mode **/ + Bool_t triggered; + if (mTriggerMode == kTriggerOFF) { + return kTRUE; + } else if (mTriggerMode == kTriggerOR) { + triggered = kFALSE; + } else if (mTriggerMode == kTriggerAND) { + triggered = kTRUE; + } else { + return kTRUE; + } - /** check trigger presence **/ - if (mTriggers.size() == 0 && mDeepTriggers.size() == 0) { - return kTRUE; + /** loop over triggers **/ + for (const auto& trigger : mTriggers) { + auto retval = trigger(mParticles); + if (mTriggerMode == kTriggerOR) { + triggered |= retval; } - - /** check trigger mode **/ - Bool_t triggered; - if (mTriggerMode == kTriggerOFF) { - return kTRUE; - } else if (mTriggerMode == kTriggerOR) { - triggered = kFALSE; - } else if (mTriggerMode == kTriggerAND) { - triggered = kTRUE; - } else { - return kTRUE; + if (mTriggerMode == kTriggerAND) { + triggered &= retval; } + } - /** loop over triggers **/ - for (const auto& trigger : mTriggers) { - auto retval = trigger(mParticles); - if (mTriggerMode == kTriggerOR) { - triggered |= retval; - } - if (mTriggerMode == kTriggerAND) { - triggered &= retval; - } + /** loop over deep triggers **/ + for (const auto& trigger : mDeepTriggers) { + auto retval = trigger(mInterface, mInterfaceName); + if (mTriggerMode == kTriggerOR) { + triggered |= retval; } - - /** loop over deep triggers **/ - for (const auto& trigger : mDeepTriggers) { - auto retval = trigger(mInterface, mInterfaceName); - if (mTriggerMode == kTriggerOR) { - triggered |= retval; - } - if (mTriggerMode == kTriggerAND) { - triggered &= retval; - } + if (mTriggerMode == kTriggerAND) { + triggered &= retval; } - - /** return **/ - return triggered; } - /*****************************************************************/ + /** return **/ + return triggered; +} + +/*****************************************************************/ - void Generator::addSubGenerator(int subGeneratorId, std::string const& subGeneratorDescription) - { - if (subGeneratorId < 0) { - LOG(fatal) << "Sub-generator IDs must be >= 0, instead, passed value is " << subGeneratorId; - } - mSubGeneratorsIdToDesc.insert({subGeneratorId, subGeneratorDescription}); +void Generator::addSubGenerator(int subGeneratorId, std::string const& subGeneratorDescription) +{ + if (subGeneratorId < 0) { + LOG(fatal) << "Sub-generator IDs must be >= 0, instead, passed value is " << subGeneratorId; } + mSubGeneratorsIdToDesc.insert({subGeneratorId, subGeneratorDescription}); +} - /*****************************************************************/ +/*****************************************************************/ - void Generator::updateSubGeneratorInformation(o2::dataformats::MCEventHeader * header) const - { - if (mSubGeneratorId < 0) { - return; - } - header->putInfo(o2::mcgenid::GeneratorProperty::SUBGENERATORID, mSubGeneratorId); - header->putInfo>(o2::mcgenid::GeneratorProperty::SUBGENERATORDESCRIPTIONMAP, mSubGeneratorsIdToDesc); +void Generator::updateSubGeneratorInformation(o2::dataformats::MCEventHeader* header) const +{ + if (mSubGeneratorId < 0) { + return; } + header->putInfo(o2::mcgenid::GeneratorProperty::SUBGENERATORID, mSubGeneratorId); + header->putInfo>(o2::mcgenid::GeneratorProperty::SUBGENERATORDESCRIPTIONMAP, mSubGeneratorsIdToDesc); +} - /*****************************************************************/ - /*****************************************************************/ +/*****************************************************************/ +/*****************************************************************/ } /* namespace eventgen */ } /* namespace o2 */ diff --git a/Generators/src/GeneratorsLinkDef.h b/Generators/src/GeneratorsLinkDef.h index 97896d8225042..2b8d42f86bf9b 100644 --- a/Generators/src/GeneratorsLinkDef.h +++ b/Generators/src/GeneratorsLinkDef.h @@ -35,10 +35,6 @@ #pragma link C++ class o2::eventgen::GeneratorFromEventPool + ; #pragma link C++ class o2::eventgen::GeneratorEventPoolParam + ; #pragma link C++ class o2::eventgen::EventPoolGenConfig + ; -#ifdef GENERATORS_WITH_ONNXRUNTIME -#pragma link C++ class o2::eventgen::GenTPCLoopers + ; -#pragma link C++ class o2::eventgen::GenTPCLoopersParam + ; -#endif #pragma link C++ class o2::conf::ConfigurableParamPromoter < o2::eventgen::GeneratorEventPoolParam, o2::eventgen::EventPoolGenConfig> + ; #ifdef GENERATORS_WITH_HEPMC3 #pragma link C++ class o2::eventgen::GeneratorHepMC + ; diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx deleted file mode 100644 index 4eacb7674599c..0000000000000 --- a/Generators/src/TPCLoopers.cxx +++ /dev/null @@ -1,417 +0,0 @@ -#include "Generators/TPCLoopers.h" - -// Static Ort::Env instance for multiple onnx model loading -Ort::Env global_env(ORT_LOGGING_LEVEL_WARNING, "GlobalEnv"); - -// This class is responsible for loading the scaler parameters from a JSON file -// and applying the inverse transformation to the generated data. - -void Scaler::load(const std::string &filename) -{ - std::ifstream file(filename); - if (!file.is_open()) { - throw std::runtime_error("Error: Could not open scaler file!"); - } - - std::string json_str((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - file.close(); - - rapidjson::Document doc; - doc.Parse(json_str.c_str()); - - if (doc.HasParseError()) { - throw std::runtime_error("Error: JSON parsing failed!"); - } - - normal_min = jsonArrayToVector(doc["normal"]["min"]); - normal_max = jsonArrayToVector(doc["normal"]["max"]); - outlier_center = jsonArrayToVector(doc["outlier"]["center"]); - outlier_scale = jsonArrayToVector(doc["outlier"]["scale"]); - std::vector normal_min; - std::vector normal_max; - std::vector outlier_center; - std::vector outlier_scale; -} - -std::vector Scaler::inverse_transform(const std::vector &input) -{ - std::vector output; - for (int i = 0; i < input.size(); ++i) - { - if (i < input.size() - 2) - output.push_back(input[i] * (normal_max[i] - normal_min[i]) + normal_min[i]); - else - output.push_back(input[i] * outlier_scale[i - (input.size() - 2)] + outlier_center[i - (input.size() - 2)]); - } - - return output; -} - -std::vector Scaler::jsonArrayToVector(const rapidjson::Value &jsonArray) -{ - std::vector vec; - for (int i = 0; i < jsonArray.Size(); ++i) - { - vec.push_back(jsonArray[i].GetDouble()); - } - return vec; -} - -// This class loads the ONNX model and generates samples using it. - -ONNXGenerator::ONNXGenerator(Ort::Env& shared_env, const std::string& model_path) -: env(shared_env), session(env, model_path.c_str(), Ort::SessionOptions{}) -{ - // Create session options - Ort::SessionOptions session_options; - session = Ort::Session(env, model_path.c_str(), session_options); -} - -std::vector ONNXGenerator::generate_sample() -{ - Ort::AllocatorWithDefaultOptions allocator; - - // Generate a latent vector (z) - std::vector z(100); - for (auto &v : z) - v = rand_gen.Gaus(0.0, 1.0); - - // Prepare input tensor - std::vector input_shape = {1, 100}; - // Get memory information - Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); - - // Create input tensor correctly - Ort::Value input_tensor = Ort::Value::CreateTensor( - memory_info, z.data(), z.size(), input_shape.data(), input_shape.size()); - // Run inference - const char *input_names[] = {"z"}; - const char *output_names[] = {"output"}; - auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_names, &input_tensor, 1, output_names, 1); - - // Extract output - float *output_data = output_tensors.front().GetTensorMutableData(); - // Get the size of the output tensor - auto output_tensor_info = output_tensors.front().GetTensorTypeAndShapeInfo(); - size_t output_data_size = output_tensor_info.GetElementCount(); // Total number of elements in the tensor - std::vector output; - for (int i = 0; i < output_data_size; ++i) - { - output.push_back(output_data[i]); - } - - return output; -} - -namespace o2 -{ -namespace eventgen -{ - -GenTPCLoopers::GenTPCLoopers(std::string model_pairs, std::string model_compton, - std::string poisson, std::string gauss, std::string scaler_pair, - std::string scaler_compton) -{ - // Checking if the model files exist and are not empty - std::ifstream model_file[2]; - model_file[0].open(model_pairs); - model_file[1].open(model_compton); - if (!model_file[0].is_open() || model_file[0].peek() == std::ifstream::traits_type::eof()) - { - LOG(fatal) << "Error: Pairs model file is empty or does not exist!"; - exit(1); - } - if (!model_file[1].is_open() || model_file[1].peek() == std::ifstream::traits_type::eof()) - { - LOG(fatal) << "Error: Compton model file is empty or does not exist!"; - exit(1); - } - model_file[0].close(); - model_file[1].close(); - // Checking if the scaler files exist and are not empty - std::ifstream scaler_file[2]; - scaler_file[0].open(scaler_pair); - scaler_file[1].open(scaler_compton); - if (!scaler_file[0].is_open() || scaler_file[0].peek() == std::ifstream::traits_type::eof()) - { - LOG(fatal) << "Error: Pairs scaler file is empty or does not exist!"; - exit(1); - } - if (!scaler_file[1].is_open() || scaler_file[1].peek() == std::ifstream::traits_type::eof()) - { - LOG(fatal) << "Error: Compton scaler file is empty or does not exist!"; - exit(1); - } - scaler_file[0].close(); - scaler_file[1].close(); - // Checking if the poisson file exists and it's not empty - if (poisson != "") - { - std::ifstream poisson_file(poisson); - if (!poisson_file.is_open() || poisson_file.peek() == std::ifstream::traits_type::eof()) - { - LOG(fatal) << "Error: Poisson file is empty or does not exist!"; - exit(1); - } - else - { - poisson_file >> mPoisson[0] >> mPoisson[1] >> mPoisson[2]; - poisson_file.close(); - mPoissonSet = true; - } - } - // Checking if the gauss file exists and it's not empty - if (gauss != "") - { - std::ifstream gauss_file(gauss); - if (!gauss_file.is_open() || gauss_file.peek() == std::ifstream::traits_type::eof()) - { - LOG(fatal) << "Error: Gauss file is empty or does not exist!"; - exit(1); - } - else - { - gauss_file >> mGauss[0] >> mGauss[1] >> mGauss[2] >> mGauss[3]; - gauss_file.close(); - mGaussSet = true; - } - } - mONNX_pair = std::make_unique(global_env, model_pairs); - mScaler_pair = std::make_unique(); - mScaler_pair->load(scaler_pair); - mONNX_compton = std::make_unique(global_env, model_compton); - mScaler_compton = std::make_unique(); - mScaler_compton->load(scaler_compton); -} - -Bool_t GenTPCLoopers::generateEvent() -{ - // Clear the vector of pairs - mGenPairs.clear(); - // Clear the vector of compton electrons - mGenElectrons.clear(); - if (mFlatGas) { - unsigned int nLoopers, nLoopersPairs, nLoopersCompton; - LOG(debug) << "mCurrentEvent is " << mCurrentEvent; - LOG(debug) << "Current event time: " << ((mCurrentEvent < mInteractionTimeRecords.size() - 1) ? std::to_string(mInteractionTimeRecords[mCurrentEvent + 1].bc2ns() - mInteractionTimeRecords[mCurrentEvent].bc2ns()) : std::to_string(mTimeEnd - mInteractionTimeRecords[mCurrentEvent].bc2ns())) << " ns"; - LOG(debug) << "Current time offset wrt BC: " << mInteractionTimeRecords[mCurrentEvent].getTimeOffsetWrtBC() << " ns"; - mTimeLimit = (mCurrentEvent < mInteractionTimeRecords.size() - 1) ? mInteractionTimeRecords[mCurrentEvent + 1].bc2ns() - mInteractionTimeRecords[mCurrentEvent].bc2ns() : mTimeEnd - mInteractionTimeRecords[mCurrentEvent].bc2ns(); - // With flat gas the number of loopers are adapted based on time interval widths - nLoopers = mFlatGasNumber * (mTimeLimit / mIntTimeRecMean); - nLoopersPairs = static_cast(std::round(nLoopers * mLoopsFractionPairs)); - nLoopersCompton = nLoopers - nLoopersPairs; - SetNLoopers(nLoopersPairs, nLoopersCompton); - LOG(info) << "Flat gas loopers: " << nLoopers << " (pairs: " << nLoopersPairs << ", compton: " << nLoopersCompton << ")"; - generateEvent(mTimeLimit); - mCurrentEvent++; - } else { - // Set number of loopers if poissonian params are available - if (mPoissonSet) { - mNLoopersPairs = static_cast(std::round(mMultiplier[0] * PoissonPairs())); - } - if (mGaussSet) { - mNLoopersCompton = static_cast(std::round(mMultiplier[1] * GaussianElectrons())); - } - // Generate pairs - for (int i = 0; i < mNLoopersPairs; ++i) { - std::vector pair = mONNX_pair->generate_sample(); - // Apply the inverse transformation using the scaler - std::vector transformed_pair = mScaler_pair->inverse_transform(pair); - mGenPairs.push_back(transformed_pair); - } - // Generate compton electrons - for (int i = 0; i < mNLoopersCompton; ++i) { - std::vector electron = mONNX_compton->generate_sample(); - // Apply the inverse transformation using the scaler - std::vector transformed_electron = mScaler_compton->inverse_transform(electron); - mGenElectrons.push_back(transformed_electron); - } - } - return true; -} - -Bool_t GenTPCLoopers::generateEvent(double& time_limit) -{ - LOG(info) << "Time constraint for loopers: " << time_limit << " ns"; - // Generate pairs - for (int i = 0; i < mNLoopersPairs; ++i) { - std::vector pair = mONNX_pair->generate_sample(); - // Apply the inverse transformation using the scaler - std::vector transformed_pair = mScaler_pair->inverse_transform(pair); - transformed_pair[9] = gRandom->Uniform(0., time_limit); // Regenerate time, scaling is not needed because time_limit is already in nanoseconds - mGenPairs.push_back(transformed_pair); - } - // Generate compton electrons - for (int i = 0; i < mNLoopersCompton; ++i) { - std::vector electron = mONNX_compton->generate_sample(); - // Apply the inverse transformation using the scaler - std::vector transformed_electron = mScaler_compton->inverse_transform(electron); - transformed_electron[6] = gRandom->Uniform(0., time_limit); // Regenerate time, scaling is not needed because time_limit is already in nanoseconds - mGenElectrons.push_back(transformed_electron); - } - LOG(info) << "Generated Particles with time limit"; - return true; -} - -std::vector GenTPCLoopers::importParticles() -{ - std::vector particles; - // Get looper pairs from the event - for (auto& pair : mGenPairs) { - double px_e, py_e, pz_e, px_p, py_p, pz_p; - double vx, vy, vz, time; - double e_etot, p_etot; - px_e = pair[0]; - py_e = pair[1]; - pz_e = pair[2]; - px_p = pair[3]; - py_p = pair[4]; - pz_p = pair[5]; - vx = pair[6]; - vy = pair[7]; - vz = pair[8]; - time = pair[9]; - e_etot = TMath::Sqrt(px_e * px_e + py_e * py_e + pz_e * pz_e + mMass_e * mMass_e); - p_etot = TMath::Sqrt(px_p * px_p + py_p * py_p + pz_p * pz_p + mMass_p * mMass_p); - // Push the electron - TParticle electron(11, 1, -1, -1, -1, -1, px_e, py_e, pz_e, e_etot, vx, vy, vz, time / 1e9); - electron.SetStatusCode(o2::mcgenstatus::MCGenStatusEncoding(electron.GetStatusCode(), 0).fullEncoding); - electron.SetBit(ParticleStatus::kToBeDone, // - o2::mcgenstatus::getHepMCStatusCode(electron.GetStatusCode()) == 1); - particles.push_back(electron); - // Push the positron - TParticle positron(-11, 1, -1, -1, -1, -1, px_p, py_p, pz_p, p_etot, vx, vy, vz, time / 1e9); - positron.SetStatusCode(o2::mcgenstatus::MCGenStatusEncoding(positron.GetStatusCode(), 0).fullEncoding); - positron.SetBit(ParticleStatus::kToBeDone, // - o2::mcgenstatus::getHepMCStatusCode(positron.GetStatusCode()) == 1); - particles.push_back(positron); - } - // Get compton electrons from the event - for (auto& compton : mGenElectrons) { - double px, py, pz; - double vx, vy, vz, time; - double etot; - px = compton[0]; - py = compton[1]; - pz = compton[2]; - vx = compton[3]; - vy = compton[4]; - vz = compton[5]; - time = compton[6]; - etot = TMath::Sqrt(px * px + py * py + pz * pz + mMass_e * mMass_e); - // Push the electron - TParticle electron(11, 1, -1, -1, -1, -1, px, py, pz, etot, vx, vy, vz, time / 1e9); - electron.SetStatusCode(o2::mcgenstatus::MCGenStatusEncoding(electron.GetStatusCode(), 0).fullEncoding); - electron.SetBit(ParticleStatus::kToBeDone, // - o2::mcgenstatus::getHepMCStatusCode(electron.GetStatusCode()) == 1); - particles.push_back(electron); - } - - return particles; -} - -unsigned int GenTPCLoopers::PoissonPairs() -{ - unsigned int poissonValue; - do { - // Generate a Poisson-distributed random number with mean mPoisson[0] - poissonValue = mRandGen.Poisson(mPoisson[0]); - } while (poissonValue < mPoisson[1] || poissonValue > mPoisson[2]); // Regenerate if out of range - - return poissonValue; -} - -unsigned int GenTPCLoopers::GaussianElectrons() -{ - unsigned int gaussValue; - do { - // Generate a Normal-distributed random number with mean mGass[0] and stddev mGauss[1] - gaussValue = mRandGen.Gaus(mGauss[0], mGauss[1]); - } while (gaussValue < mGauss[2] || gaussValue > mGauss[3]); // Regenerate if out of range - - return gaussValue; -} - -void GenTPCLoopers::SetNLoopers(unsigned int& nsig_pair, unsigned int& nsig_compton) -{ - if (mFlatGas) { - mNLoopersPairs = nsig_pair; - mNLoopersCompton = nsig_compton; - } else { - if (mPoissonSet) { - LOG(info) << "Poissonian parameters correctly loaded."; - } else { - mNLoopersPairs = nsig_pair; - } - if (mGaussSet) { - LOG(info) << "Gaussian parameters correctly loaded."; - } else { - mNLoopersCompton = nsig_compton; - } - } -} - -void GenTPCLoopers::SetMultiplier(std::array& mult) -{ - // Multipliers will work only if the poissonian and gaussian parameters are set - // otherwise they will be ignored - if (mult[0] < 0 || mult[1] < 0) - { - LOG(fatal) << "Error: Multiplier values must be non-negative!"; - exit(1); - } else { - LOG(info) << "Multiplier values set to: Pair = " << mult[0] << ", Compton = " << mult[1]; - mMultiplier[0] = mult[0]; - mMultiplier[1] = mult[1]; - } -} - -void GenTPCLoopers::setFlatGas(Bool_t& flat, const Int_t& number) -{ - mFlatGas = flat; - if (mFlatGas) { - if (number < 0) { - LOG(warn) << "Warning: Number of loopers per event must be non-negative! Switching option off."; - mFlatGas = false; - mFlatGasNumber = -1; - } else { - mFlatGasNumber = number; - mContextFile = std::filesystem::exists("collisioncontext.root") ? TFile::Open("collisioncontext.root") : nullptr; - mCollisionContext = mContextFile ? (o2::steer::DigitizationContext*)mContextFile->Get("DigitizationContext") : nullptr; - mInteractionTimeRecords = mCollisionContext ? mCollisionContext->getEventRecords() : std::vector{}; - if (mInteractionTimeRecords.empty()) { - LOG(error) << "Error: No interaction time records found in the collision context!"; - exit(1); - } else { - LOG(info) << "Interaction Time records has " << mInteractionTimeRecords.size() << " entries."; - mCollisionContext->printCollisionSummary(); - } - for (int c = 0; c < mInteractionTimeRecords.size() - 1; c++) { - mIntTimeRecMean += mInteractionTimeRecords[c + 1].bc2ns() - mInteractionTimeRecords[c].bc2ns(); - } - mIntTimeRecMean /= (mInteractionTimeRecords.size() - 1); // Average interaction time record used as reference - const auto& hbfUtils = o2::raw::HBFUtils::Instance(); - // Get the start time of the second orbit after the last interaction record - const auto& lastIR = mInteractionTimeRecords.back(); - o2::InteractionRecord finalOrbitIR(0, lastIR.orbit + 2); // Final orbit, BC = 0 - mTimeEnd = finalOrbitIR.bc2ns(); - LOG(debug) << "Final orbit start time: " << mTimeEnd << " ns while last interaction record time is " << mInteractionTimeRecords.back().bc2ns() << " ns"; - } - } else { - mFlatGasNumber = -1; - } - LOG(info) << "Flat gas loopers: " << (mFlatGas ? "ON" : "OFF") << ", Reference loopers number per event: " << mFlatGasNumber; -} - -void GenTPCLoopers::setFractionPairs(float& fractionPairs) -{ - if (fractionPairs < 0 || fractionPairs > 1) { - LOG(fatal) << "Error: Loops fraction for pairs must be in the range [0, 1]."; - exit(1); - } - mLoopsFractionPairs = fractionPairs; - LOG(info) << "Pairs fraction set to: " << mLoopsFractionPairs; -} - -} // namespace eventgen -} // namespace o2 \ No newline at end of file diff --git a/Generators/src/TPCLoopersParam.cxx b/Generators/src/TPCLoopersParam.cxx deleted file mode 100644 index 0202a8ced0535..0000000000000 --- a/Generators/src/TPCLoopersParam.cxx +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2024-2025 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \author M+Giacalone - September 2025 - -#include "Generators/TPCLoopersParam.h" -O2ParamImpl(o2::eventgen::GenTPCLoopersParam); From 51f8cefb58b705ba534d65bee42528c0a5d4221a Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Wed, 17 Dec 2025 14:17:57 +0100 Subject: [PATCH 053/234] Moved configFile check + expand env vars --- Generators/src/GeneratorFactory.cxx | 5 ----- Generators/src/GeneratorHybrid.cxx | 12 +++++++++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Generators/src/GeneratorFactory.cxx b/Generators/src/GeneratorFactory.cxx index 4102bd8ffd9b2..d04e785402915 100644 --- a/Generators/src/GeneratorFactory.cxx +++ b/Generators/src/GeneratorFactory.cxx @@ -279,11 +279,6 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair LOG(fatal) << "No configuration file provided for hybrid generator"; return; } - // check if file named config exists and it's not empty - else if (gSystem->AccessPathName(config.c_str())) { - LOG(fatal) << "Configuration file for hybrid generator does not exist"; - return; - } auto& hybrid = o2::eventgen::GeneratorHybrid::Instance(config); primGen->AddGenerator(&hybrid); #endif diff --git a/Generators/src/GeneratorHybrid.cxx b/Generators/src/GeneratorHybrid.cxx index 370671a977a5c..2a13f9876e717 100644 --- a/Generators/src/GeneratorHybrid.cxx +++ b/Generators/src/GeneratorHybrid.cxx @@ -615,17 +615,23 @@ Bool_t GeneratorHybrid::confSetter(const auto& gen) Bool_t GeneratorHybrid::parseJSON(const std::string& path) { + auto expandedPath = o2::utils::expandShellVarsInFileName(path); + // Check if configuration file exists + if (gSystem->AccessPathName(expandedPath.c_str())) { + LOG(fatal) << "Configuration file " << expandedPath << " for hybrid generator does not exist"; + return false; + } // Parse JSON file to build map - std::ifstream fileStream(path, std::ios::in); + std::ifstream fileStream(expandedPath, std::ios::in); if (!fileStream.is_open()) { - LOG(error) << "Cannot open " << path; + LOG(error) << "Cannot open " << expandedPath; return false; } rapidjson::IStreamWrapper isw(fileStream); rapidjson::Document doc; doc.ParseStream(isw); if (doc.HasParseError()) { - LOG(error) << "Error parsing provided json file " << path; + LOG(error) << "Error parsing provided json file " << expandedPath; LOG(error) << " - Error -> " << rapidjson::GetParseError_En(doc.GetParseError()); return false; } From 7211829480227b643715c57b2ac5e80a6bd17846 Mon Sep 17 00:00:00 2001 From: Ernst Hellbar Date: Tue, 2 Dec 2025 10:14:58 +0100 Subject: [PATCH 054/234] dpl-workflow.sh: add relaxed GPU_rec_tpc async cuts also as default for sync --- prodtests/full-system-test/dpl-workflow.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index 754349c87eecc..db491da5ebec5 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -145,6 +145,8 @@ if [[ $SYNCMODE == 1 ]]; then fi fi GPU_CONFIG_KEY+="GPU_global.synchronousProcessing=1;GPU_proc.clearO2OutputFromGPU=1;" + # relaxed cuts also used for async reconstruction, they require scaling of the GPU memory + GPU_CONFIG_KEY+="GPU_rec_tpc.trackletMinSharedNormFactor=1.;GPU_rec_tpc.trackletMaxSharedFraction=0.3;GPU_rec_tpc.rejectIFCLowRadiusCluster=1;GPU_rec_tpc.extrapolationTrackingRowRange=100;GPU_rec_tpc.clusterError2AdditionalYSeeding=0.1;GPU_rec_tpc.clusterError2AdditionalZSeeding=0.15;GPU_proc.memoryScalingFactor=1.2;" has_processing_step TPC_DEDX && GPU_CONFIG_KEY+="GPU_global.rundEdx=1;" has_detector ITS && TRD_FILTER_CONFIG+=" --filter-trigrec" else From 35b0becfa59f1d9be85f65a2ca829f99e93ef5f0 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Mon, 15 Dec 2025 11:02:17 +0100 Subject: [PATCH 055/234] Fix code checker issue --- Detectors/ITSMFT/ITS/postprocessing/studies/src/PIDStudy.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/PIDStudy.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/PIDStudy.cxx index 4b0f553eb774b..9a7f6c218cd12 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/PIDStudy.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/PIDStudy.cxx @@ -91,7 +91,7 @@ class PIDStudy : public Task std::shared_ptr gr, bool isMC, std::shared_ptr kineReader) : mDataRequest{dr}, mGGCCDBRequest(gr), mUseMC(isMC), mKineReader(kineReader){}; - ~PIDStudy() final = default; + ~PIDStudy() override = default; void init(InitContext& ic) final; void run(ProcessingContext&) final; void endOfStream(EndOfStreamContext&) final; From ea23c378e45c2e2c84a707cd03abd044e52572ea Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Mon, 15 Dec 2025 11:02:17 +0100 Subject: [PATCH 056/234] MathUtils: move BetheBlochAleph to a common header --- .../include/MathUtils/BetheBlochAleph.h | 35 +++++++++++++++++++ .../include/DataFormatsTPC/BetheBlochAleph.h | 18 +++------- 2 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 Common/MathUtils/include/MathUtils/BetheBlochAleph.h diff --git a/Common/MathUtils/include/MathUtils/BetheBlochAleph.h b/Common/MathUtils/include/MathUtils/BetheBlochAleph.h new file mode 100644 index 0000000000000..bd72faffb0503 --- /dev/null +++ b/Common/MathUtils/include/MathUtils/BetheBlochAleph.h @@ -0,0 +1,35 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef AliceO2_COMMON_BETHEBLOCH_H_ +#define AliceO2_COMMON_BETHEBLOCH_H_ + +#include "GPUCommonDef.h" +#include "GPUCommonMath.h" + +namespace o2::common +{ + +template +GPUdi() T BetheBlochAleph(T bg, T kp1, T kp2, T kp3, T kp4, T kp5) +{ + T beta = bg / o2::gpu::GPUCommonMath::Sqrt(static_cast(1.) + bg * bg); + + T aa = o2::gpu::GPUCommonMath::Pow(beta, kp4); + T bb = o2::gpu::GPUCommonMath::Pow(static_cast(1.) / bg, kp5); + bb = o2::gpu::GPUCommonMath::Log(kp3 + bb); + + return (kp2 - aa - bb) * kp1 / aa; +} + +} // namespace o2::common + +#endif diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/BetheBlochAleph.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/BetheBlochAleph.h index e8fe7457f3091..28b224298f36f 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/BetheBlochAleph.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/BetheBlochAleph.h @@ -12,27 +12,17 @@ #ifndef AliceO2_TPC_BETHEBLOCH_H_ #define AliceO2_TPC_BETHEBLOCH_H_ -#include "GPUCommonDef.h" -#include "GPUCommonMath.h" +#include "MathUtils/BetheBlochAleph.h" -namespace o2 -{ -namespace tpc +namespace o2::tpc { template GPUdi() T BetheBlochAleph(T bg, T kp1, T kp2, T kp3, T kp4, T kp5) { - T beta = bg / o2::gpu::GPUCommonMath::Sqrt(static_cast(1.) + bg * bg); - - T aa = o2::gpu::GPUCommonMath::Pow(beta, kp4); - T bb = o2::gpu::GPUCommonMath::Pow(static_cast(1.) / bg, kp5); - bb = o2::gpu::GPUCommonMath::Log(kp3 + bb); - - return (kp2 - aa - bb) * kp1 / aa; + return o2::common::BetheBlochAleph(bg, kp1, kp2, kp3, kp4, kp5); } -} // namespace tpc -} // namespace o2 +} // namespace o2::tpc #endif From d6f6148d1a89eb2bfd955541ffa0717178cb122e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 15:25:59 +0000 Subject: [PATCH 057/234] Bump actions/cache from 4 to 5 Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/cache dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/reports.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reports.yml b/.github/workflows/reports.yml index 936be948b7218..5a04e56382fb3 100644 --- a/.github/workflows/reports.yml +++ b/.github/workflows/reports.yml @@ -22,7 +22,7 @@ jobs: uses: actions/setup-python@v6 with: python-version: '3.10' - - uses: actions/cache@v4 + - uses: actions/cache@v5 name: Configure pip caching with: path: ~/.cache/pip From aab079f2ba980913451b4902749e8f424fcebdaa Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 6 Jan 2026 10:59:20 +0100 Subject: [PATCH 058/234] DataModel: improve DataHeader formatter Add splitPayloadIndex / splitPayloadParts to the default printout --- DataFormats/Headers/include/Headers/DataHeaderHelpers.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DataFormats/Headers/include/Headers/DataHeaderHelpers.h b/DataFormats/Headers/include/Headers/DataHeaderHelpers.h index aa93414cfb99f..4f7e49acb4d98 100644 --- a/DataFormats/Headers/include/Headers/DataHeaderHelpers.h +++ b/DataFormats/Headers/include/Headers/DataHeaderHelpers.h @@ -79,7 +79,8 @@ struct fmt::formatter { fmt::format(" payloadSize : {}\n", (long long unsigned int)h.payloadSize) + fmt::format(" firstTForbit : {}\n", h.firstTForbit) + fmt::format(" tfCounter : {}\n", h.tfCounter) + - fmt::format(" runNumber : {}\n", h.runNumber); + fmt::format(" runNumber : {}\n", h.runNumber) + + fmt::format(" split : {}/{}\n", h.splitPayloadIndex, h.splitPayloadParts); return fmt::format_to(ctx.out(), "{}", res); } else { auto res = fmt::format("{}/{}/{}", From a5f88b79468c20cf515488c3f69f98fb2839830f Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Mon, 1 Dec 2025 12:49:46 +0100 Subject: [PATCH 059/234] AnalysisContext -> DanglingEdgesContext --- .../AnalysisSupport/src/AODReaderHelpers.cxx | 6 +- .../AnalysisSupport/src/AODWriterHelpers.cxx | 6 +- .../CCDBSupport/src/AnalysisCCDBHelpers.cxx | 4 +- .../Framework/AnalysisSupportHelpers.h | 2 +- ...alysisContext.h => DanglingEdgesContext.h} | 8 +- Framework/Core/src/AnalysisSupportHelpers.cxx | 6 +- Framework/Core/src/ArrowSupport.cxx | 64 +++++++------- Framework/Core/src/WorkflowHelpers.cxx | 85 +++++++++---------- 8 files changed, 90 insertions(+), 91 deletions(-) rename Framework/Core/include/Framework/{AnalysisContext.h => DanglingEdgesContext.h} (92%) diff --git a/Framework/AnalysisSupport/src/AODReaderHelpers.cxx b/Framework/AnalysisSupport/src/AODReaderHelpers.cxx index 40aa5a9537c7f..045ef072a3040 100644 --- a/Framework/AnalysisSupport/src/AODReaderHelpers.cxx +++ b/Framework/AnalysisSupport/src/AODReaderHelpers.cxx @@ -19,7 +19,7 @@ #include "Framework/AlgorithmSpec.h" #include "Framework/DataSpecUtils.h" #include "Framework/ConfigContext.h" -#include "Framework/AnalysisContext.h" +#include "Framework/DanglingEdgesContext.h" namespace o2::framework::readers { @@ -81,7 +81,7 @@ struct Buildable { AlgorithmSpec AODReaderHelpers::indexBuilderCallback(ConfigContext const& ctx) { - auto& ac = ctx.services().get(); + auto& ac = ctx.services().get(); return AlgorithmSpec::InitCallback{[requested = ac.requestedIDXs](InitContext& /*ic*/) { std::vector buildables; for (auto& i : requested) { @@ -183,7 +183,7 @@ struct Spawnable { AlgorithmSpec AODReaderHelpers::aodSpawnerCallback(ConfigContext const& ctx) { - auto& ac = ctx.services().get(); + auto& ac = ctx.services().get(); return AlgorithmSpec::InitCallback{[requested = ac.spawnerInputs](InitContext& /*ic*/) { std::vector spawnables; for (auto& i : requested) { diff --git a/Framework/AnalysisSupport/src/AODWriterHelpers.cxx b/Framework/AnalysisSupport/src/AODWriterHelpers.cxx index bcf27d0be5ba3..5a43683afd364 100644 --- a/Framework/AnalysisSupport/src/AODWriterHelpers.cxx +++ b/Framework/AnalysisSupport/src/AODWriterHelpers.cxx @@ -8,7 +8,7 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "Framework/AnalysisContext.h" +#include "Framework/DanglingEdgesContext.h" #include "Framework/ConfigContext.h" #include "Framework/ControlService.h" #include "AODWriterHelpers.h" @@ -62,7 +62,7 @@ const static std::unordered_map ROOTfileNa AlgorithmSpec AODWriterHelpers::getOutputTTreeWriter(ConfigContext const& ctx) { - auto& ac = ctx.services().get(); + auto& ac = ctx.services().get(); auto dod = AnalysisSupportHelpers::getDataOutputDirector(ctx); int compressionLevel = 505; if (ctx.options().hasOption("aod-writer-compression")) { @@ -245,7 +245,7 @@ AlgorithmSpec AODWriterHelpers::getOutputTTreeWriter(ConfigContext const& ctx) AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& ctx) { using namespace monitoring; - auto& ac = ctx.services().get(); + auto& ac = ctx.services().get(); auto tskmap = ac.outTskMap; auto objmap = ac.outObjHistMap; diff --git a/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx b/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx index aba1f3ed4e13d..fcc856669cd92 100644 --- a/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx +++ b/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx @@ -18,7 +18,7 @@ #include "Framework/RawDeviceService.h" #include "Framework/Output.h" #include "Framework/Signpost.h" -#include "Framework/AnalysisContext.h" +#include "Framework/DanglingEdgesContext.h" #include "Framework/ConfigContext.h" #include "Framework/ConfigContext.h" #include @@ -69,7 +69,7 @@ void fillValidRoutes(CCDBFetcherHelper& helper, std::vector(); + auto& ac = ctx.services().get(); std::vector> schemas; auto schemaMetadata = std::make_shared(); diff --git a/Framework/Core/include/Framework/AnalysisSupportHelpers.h b/Framework/Core/include/Framework/AnalysisSupportHelpers.h index c0eeb3bd9697d..ef1d056b62f2b 100644 --- a/Framework/Core/include/Framework/AnalysisSupportHelpers.h +++ b/Framework/Core/include/Framework/AnalysisSupportHelpers.h @@ -14,7 +14,7 @@ #include "Framework/OutputSpec.h" #include "Framework/InputSpec.h" #include "Framework/DataProcessorSpec.h" -#include "Framework/AnalysisContext.h" +#include "Framework/DanglingEdgesContext.h" #include "Headers/DataHeader.h" #include diff --git a/Framework/Core/include/Framework/AnalysisContext.h b/Framework/Core/include/Framework/DanglingEdgesContext.h similarity index 92% rename from Framework/Core/include/Framework/AnalysisContext.h rename to Framework/Core/include/Framework/DanglingEdgesContext.h index 7d1544ed312a4..90a88974db038 100644 --- a/Framework/Core/include/Framework/AnalysisContext.h +++ b/Framework/Core/include/Framework/DanglingEdgesContext.h @@ -8,8 +8,8 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef O2_FRAMEWORK_ANALYSISCONTEXT_H_ -#define O2_FRAMEWORK_ANALYSISCONTEXT_H_ +#ifndef O2_FRAMEWORK_DANGLINGEDGESCONTEXT_H_ +#define O2_FRAMEWORK_DANGLINGEDGESCONTEXT_H_ #include #include "Framework/InputSpec.h" @@ -32,7 +32,7 @@ struct OutputObjectInfo { // This will keep track of the inputs which have // been requested and for which we will need to inject // some source device. -struct AnalysisContext { +struct DanglingEdgesContext { std::vector requestedAODs; std::vector providedAODs; std::vector requestedDYNs; @@ -63,4 +63,4 @@ struct AnalysisContext { extern template class std::vector; extern template class std::vector; -#endif // O2_FRAMEWORK_ANALYSISCONTEXT_H_ +#endif // O2_FRAMEWORK_DANGLINGEDGESCONTEXT_H_ diff --git a/Framework/Core/src/AnalysisSupportHelpers.cxx b/Framework/Core/src/AnalysisSupportHelpers.cxx index e59f36c72bdab..15b56f9afbff5 100644 --- a/Framework/Core/src/AnalysisSupportHelpers.cxx +++ b/Framework/Core/src/AnalysisSupportHelpers.cxx @@ -25,8 +25,8 @@ namespace o2::framework std::shared_ptr AnalysisSupportHelpers::getDataOutputDirector(ConfigContext const& ctx) { auto const& options = ctx.options(); - auto const& OutputsInputs = ctx.services().get().outputsInputs; - auto const& isDangling = ctx.services().get().isDangling; + auto const& OutputsInputs = ctx.services().get().outputsInputs; + auto const& isDangling = ctx.services().get().isDangling; std::shared_ptr dod = std::make_shared(); @@ -200,7 +200,7 @@ DataProcessorSpec AnalysisSupportHelpers::getOutputObjHistSink(ConfigContext con DataProcessorSpec AnalysisSupportHelpers::getGlobalAODSink(ConfigContext const& ctx) { - auto& ac = ctx.services().get(); + auto& ac = ctx.services().get(); // the command line options relevant for the writer are global // see runDataProcessing.h diff --git a/Framework/Core/src/ArrowSupport.cxx b/Framework/Core/src/ArrowSupport.cxx index 26594252e888b..ee4275281ab31 100644 --- a/Framework/Core/src/ArrowSupport.cxx +++ b/Framework/Core/src/ArrowSupport.cxx @@ -588,23 +588,23 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() auto builder = std::find_if(workflow.begin(), workflow.end(), [](DataProcessorSpec const& spec) { return spec.name == "internal-dpl-aod-index-builder"; }); auto reader = std::find_if(workflow.begin(), workflow.end(), [](DataProcessorSpec const& spec) { return spec.name == "internal-dpl-aod-reader"; }); auto writer = std::find_if(workflow.begin(), workflow.end(), [](DataProcessorSpec const& spec) { return spec.name == "internal-dpl-aod-writer"; }); - auto &ac = ctx.services().get(); - ac.requestedAODs.clear(); - ac.requestedDYNs.clear(); - ac.providedDYNs.clear(); - ac.providedTIMs.clear(); - ac.requestedTIMs.clear(); + auto& dec = ctx.services().get(); + dec.requestedAODs.clear(); + dec.requestedDYNs.clear(); + dec.providedDYNs.clear(); + dec.providedTIMs.clear(); + dec.requestedTIMs.clear(); auto inputSpecLessThan = [](InputSpec const& lhs, InputSpec const& rhs) { return DataSpecUtils::describe(lhs) < DataSpecUtils::describe(rhs); }; auto outputSpecLessThan = [](OutputSpec const& lhs, OutputSpec const& rhs) { return DataSpecUtils::describe(lhs) < DataSpecUtils::describe(rhs); }; if (builder != workflow.end()) { // collect currently requested IDXs - ac.requestedIDXs.clear(); + dec.requestedIDXs.clear(); for (auto& d : workflow | views::exclude_by_name(builder->name)) { d.inputs | views::partial_match_filter(header::DataOrigin{"IDX"}) | - sinks::update_input_list{ac.requestedIDXs}; + sinks::update_input_list{dec.requestedIDXs}; } // recreate inputs and outputs builder->inputs.clear(); @@ -612,7 +612,7 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() // replace AlgorithmSpec // FIXME: it should be made more generic, so it does not need replacement... builder->algorithm = PluginManager::loadAlgorithmFromPlugin("O2FrameworkOnDemandTablesSupport", "IndexTableBuilder", ctx); // readers::AODReaderHelpers::indexBuilderCallback(ctx); - AnalysisSupportHelpers::addMissingOutputsToBuilder(ac.requestedIDXs, ac.requestedAODs, ac.requestedDYNs, *builder); + AnalysisSupportHelpers::addMissingOutputsToBuilder(dec.requestedIDXs, dec.requestedAODs, dec.requestedDYNs, *builder); } if (spawner != workflow.end()) { @@ -620,21 +620,21 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() for (auto& d : workflow | views::exclude_by_name(spawner->name)) { d.inputs | views::partial_match_filter(header::DataOrigin{"DYN"}) | - sinks::update_input_list{ac.requestedDYNs}; + sinks::update_input_list{dec.requestedDYNs}; d.outputs | views::partial_match_filter(header::DataOrigin{"DYN"}) | - sinks::append_to{ac.providedDYNs}; + sinks::append_to{dec.providedDYNs}; } - std::sort(ac.requestedDYNs.begin(), ac.requestedDYNs.end(), inputSpecLessThan); - std::sort(ac.providedDYNs.begin(), ac.providedDYNs.end(), outputSpecLessThan); - ac.spawnerInputs.clear(); - ac.requestedDYNs | - views::filter_not_matching(ac.providedDYNs) | - sinks::append_to{ac.spawnerInputs}; + std::sort(dec.requestedDYNs.begin(), dec.requestedDYNs.end(), inputSpecLessThan); + std::sort(dec.providedDYNs.begin(), dec.providedDYNs.end(), outputSpecLessThan); + dec.spawnerInputs.clear(); + dec.requestedDYNs | + views::filter_not_matching(dec.providedDYNs) | + sinks::append_to{dec.spawnerInputs}; // recreate inputs and outputs spawner->outputs.clear(); spawner->inputs.clear(); - AnalysisSupportHelpers::addMissingOutputsToSpawner({}, ac.spawnerInputs, ac.requestedAODs, *spawner); + AnalysisSupportHelpers::addMissingOutputsToSpawner({}, dec.spawnerInputs, dec.requestedAODs, *spawner); // replace AlgorithmSpec // FIXME: it should be made more generic, so it does not need replacement... spawner->algorithm = PluginManager::loadAlgorithmFromPlugin("O2FrameworkOnDemandTablesSupport", "ExtendedTableSpawner", ctx); @@ -642,14 +642,14 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() if (analysisCCDB != workflow.end()) { for (auto& d : workflow | views::exclude_by_name(analysisCCDB->name)) { - d.inputs | views::partial_match_filter(header::DataOrigin{"ATIM"}) | sinks::update_input_list{ac.requestedTIMs}; - d.outputs | views::partial_match_filter(header::DataOrigin{"ATIM"}) | sinks::append_to{ac.providedTIMs}; + d.inputs | views::partial_match_filter(header::DataOrigin{"ATIM"}) | sinks::update_input_list{dec.requestedTIMs}; + d.outputs | views::partial_match_filter(header::DataOrigin{"ATIM"}) | sinks::append_to{dec.providedTIMs}; } - std::sort(ac.requestedTIMs.begin(), ac.requestedTIMs.end(), inputSpecLessThan); - std::sort(ac.providedTIMs.begin(), ac.providedTIMs.end(), outputSpecLessThan); + std::sort(dec.requestedTIMs.begin(), dec.requestedTIMs.end(), inputSpecLessThan); + std::sort(dec.providedTIMs.begin(), dec.providedTIMs.end(), outputSpecLessThan); // Use ranges::to> in C++23... - ac.analysisCCDBInputs.clear(); - ac.requestedTIMs | views::filter_not_matching(ac.providedTIMs) | sinks::append_to{ac.analysisCCDBInputs}; + dec.analysisCCDBInputs.clear(); + dec.requestedTIMs | views::filter_not_matching(dec.providedTIMs) | sinks::append_to{dec.analysisCCDBInputs}; // recreate inputs and outputs analysisCCDB->outputs.clear(); @@ -658,7 +658,7 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() // FIXME: it should be made more generic, so it does not need replacement... // FIXME how can I make the lookup depend on DYN tables as well?? analysisCCDB->algorithm = PluginManager::loadAlgorithmFromPlugin("O2FrameworkCCDBSupport", "AnalysisCCDBFetcherPlugin", ctx); - AnalysisSupportHelpers::addMissingOutputsToBuilder(ac.analysisCCDBInputs, ac.requestedAODs, ac.requestedDYNs, *analysisCCDB); + AnalysisSupportHelpers::addMissingOutputsToBuilder(dec.analysisCCDBInputs, dec.requestedAODs, dec.requestedDYNs, *analysisCCDB); } if (writer != workflow.end()) { @@ -671,12 +671,12 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() for (auto& d : workflow) { d.inputs | views::partial_match_filter(AODOrigins) | - sinks::update_input_list{ac.requestedAODs}; + sinks::update_input_list{dec.requestedAODs}; } // remove unmatched outputs auto o_end = std::remove_if(reader->outputs.begin(), reader->outputs.end(), [&](OutputSpec const& o) { - return !DataSpecUtils::partialMatch(o, o2::header::DataDescription{"TFNumber"}) && !DataSpecUtils::partialMatch(o, o2::header::DataDescription{"TFFilename"}) && std::none_of(ac.requestedAODs.begin(), ac.requestedAODs.end(), [&](InputSpec const& i) { return DataSpecUtils::match(i, o); }); + return !DataSpecUtils::partialMatch(o, o2::header::DataDescription{"TFNumber"}) && !DataSpecUtils::partialMatch(o, o2::header::DataDescription{"TFFilename"}) && std::none_of(dec.requestedAODs.begin(), dec.requestedAODs.end(), [&](InputSpec const& i) { return DataSpecUtils::match(i, o); }); }); reader->outputs.erase(o_end, reader->outputs.end()); if (reader->outputs.empty()) { @@ -694,22 +694,22 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() // select outputs of type AOD which need to be saved // ATTENTION: if there are dangling outputs the getGlobalAODSink // has to be created in any case! - ac.outputsInputsAOD.clear(); + dec.outputsInputsAOD.clear(); for (auto ii = 0u; ii < outputsInputs.size(); ii++) { if (DataSpecUtils::partialMatch(outputsInputs[ii], extendedAODOrigins)) { auto ds = dod->getDataOutputDescriptors(outputsInputs[ii]); if (!ds.empty() || isDangling[ii]) { - ac.outputsInputsAOD.emplace_back(outputsInputs[ii]); + dec.outputsInputsAOD.emplace_back(outputsInputs[ii]); } } } // file sink for any AOD output - if (!ac.outputsInputsAOD.empty()) { + if (!dec.outputsInputsAOD.empty()) { // add TFNumber and TFFilename as input to the writer - ac.outputsInputsAOD.emplace_back("tfn", "TFN", "TFNumber"); - ac.outputsInputsAOD.emplace_back("tff", "TFF", "TFFilename"); + dec.outputsInputsAOD.emplace_back("tfn", "TFN", "TFNumber"); + dec.outputsInputsAOD.emplace_back("tff", "TFF", "TFFilename"); workflow.push_back(AnalysisSupportHelpers::getGlobalAODSink(ctx)); } // Move the dummy sink at the end, if needed diff --git a/Framework/Core/src/WorkflowHelpers.cxx b/Framework/Core/src/WorkflowHelpers.cxx index 02141678fec7c..fdcdb6093a111 100644 --- a/Framework/Core/src/WorkflowHelpers.cxx +++ b/Framework/Core/src/WorkflowHelpers.cxx @@ -247,8 +247,8 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext aodReader.options.emplace_back(ConfigParamSpec{"channel-config", VariantType::String, rateLimitingChannelConfigInput, {"how many timeframes can be in flight at the same time"}}); } - ctx.services().registerService(ServiceRegistryHelpers::handleForService(new AnalysisContext)); - auto& ac = ctx.services().get(); + ctx.services().registerService(ServiceRegistryHelpers::handleForService(new DanglingEdgesContext)); + auto& dec = ctx.services().get(); std::vector requestedCCDBs; std::vector providedCCDBs; @@ -257,7 +257,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext auto& processor = workflow[wi]; auto name = processor.name; auto hash = runtime_hash(name.c_str()); - ac.outTskMap.push_back({hash, name}); + dec.outTskMap.push_back({hash, name}); std::string prefix = "internal-dpl-"; if (processor.inputs.empty() && processor.name.compare(0, prefix.size(), prefix) != 0) { @@ -336,16 +336,16 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext break; } if (DataSpecUtils::partialMatch(input, AODOrigins)) { - DataSpecUtils::updateInputList(ac.requestedAODs, InputSpec{input}); + DataSpecUtils::updateInputList(dec.requestedAODs, InputSpec{input}); } if (DataSpecUtils::partialMatch(input, header::DataOrigin{"DYN"})) { - DataSpecUtils::updateInputList(ac.requestedDYNs, InputSpec{input}); + DataSpecUtils::updateInputList(dec.requestedDYNs, InputSpec{input}); } if (DataSpecUtils::partialMatch(input, header::DataOrigin{"IDX"})) { - DataSpecUtils::updateInputList(ac.requestedIDXs, InputSpec{input}); + DataSpecUtils::updateInputList(dec.requestedIDXs, InputSpec{input}); } if (DataSpecUtils::partialMatch(input, header::DataOrigin{"ATIM"})) { - DataSpecUtils::updateInputList(ac.requestedTIMs, InputSpec{input}); + DataSpecUtils::updateInputList(dec.requestedTIMs, InputSpec{input}); } } @@ -353,16 +353,16 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext for (auto& output : processor.outputs) { if (DataSpecUtils::partialMatch(output, AODOrigins)) { - ac.providedAODs.emplace_back(output); + dec.providedAODs.emplace_back(output); } else if (DataSpecUtils::partialMatch(output, header::DataOrigin{"DYN"})) { - ac.providedDYNs.emplace_back(output); + dec.providedDYNs.emplace_back(output); } else if (DataSpecUtils::partialMatch(output, header::DataOrigin{"ATIM"})) { - ac.providedTIMs.emplace_back(output); + dec.providedTIMs.emplace_back(output); } else if (DataSpecUtils::partialMatch(output, header::DataOrigin{"ATSK"})) { - ac.providedOutputObjHist.emplace_back(output); - auto it = std::find_if(ac.outObjHistMap.begin(), ac.outObjHistMap.end(), [&](auto&& x) { return x.id == hash; }); - if (it == ac.outObjHistMap.end()) { - ac.outObjHistMap.push_back({hash, {output.binding.value}}); + dec.providedOutputObjHist.emplace_back(output); + auto it = std::find_if(dec.outObjHistMap.begin(), dec.outObjHistMap.end(), [&](auto&& x) { return x.id == hash; }); + if (it == dec.outObjHistMap.end()) { + dec.outObjHistMap.push_back({hash, {output.binding.value}}); } else { it->bindings.push_back(output.binding.value); } @@ -375,10 +375,10 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext auto inputSpecLessThan = [](InputSpec const& lhs, InputSpec const& rhs) { return DataSpecUtils::describe(lhs) < DataSpecUtils::describe(rhs); }; auto outputSpecLessThan = [](OutputSpec const& lhs, OutputSpec const& rhs) { return DataSpecUtils::describe(lhs) < DataSpecUtils::describe(rhs); }; - std::sort(ac.requestedDYNs.begin(), ac.requestedDYNs.end(), inputSpecLessThan); - std::sort(ac.requestedTIMs.begin(), ac.requestedTIMs.end(), inputSpecLessThan); - std::sort(ac.providedDYNs.begin(), ac.providedDYNs.end(), outputSpecLessThan); - std::sort(ac.providedTIMs.begin(), ac.providedTIMs.end(), outputSpecLessThan); + std::sort(dec.requestedDYNs.begin(), dec.requestedDYNs.end(), inputSpecLessThan); + std::sort(dec.requestedTIMs.begin(), dec.requestedTIMs.end(), inputSpecLessThan); + std::sort(dec.providedDYNs.begin(), dec.providedDYNs.end(), outputSpecLessThan); + std::sort(dec.providedTIMs.begin(), dec.providedTIMs.end(), outputSpecLessThan); DataProcessorSpec indexBuilder{ "internal-dpl-aod-index-builder", @@ -386,15 +386,15 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext {}, PluginManager::loadAlgorithmFromPlugin("O2FrameworkOnDemandTablesSupport", "IndexTableBuilder", ctx), // readers::AODReaderHelpers::indexBuilderCallback(ctx), {}}; - AnalysisSupportHelpers::addMissingOutputsToBuilder(ac.requestedIDXs, ac.requestedAODs, ac.requestedDYNs, indexBuilder); + AnalysisSupportHelpers::addMissingOutputsToBuilder(dec.requestedIDXs, dec.requestedAODs, dec.requestedDYNs, indexBuilder); - ac.requestedTIMs | views::filter_not_matching(ac.providedTIMs) | sinks::append_to{ac.analysisCCDBInputs}; + dec.requestedTIMs | views::filter_not_matching(dec.providedTIMs) | sinks::append_to{dec.analysisCCDBInputs}; DeploymentMode deploymentMode = DefaultsHelpers::deploymentMode(); if (deploymentMode != DeploymentMode::OnlineDDS && deploymentMode != DeploymentMode::OnlineECS) { - AnalysisSupportHelpers::addMissingOutputsToBuilder(ac.analysisCCDBInputs, ac.requestedAODs, ac.requestedTIMs, analysisCCDBBackend); + AnalysisSupportHelpers::addMissingOutputsToBuilder(dec.analysisCCDBInputs, dec.requestedAODs, dec.requestedTIMs, analysisCCDBBackend); } - ac.requestedDYNs | views::filter_not_matching(ac.providedDYNs) | sinks::append_to{ac.spawnerInputs}; + dec.requestedDYNs | views::filter_not_matching(dec.providedDYNs) | sinks::append_to{dec.spawnerInputs}; DataProcessorSpec aodSpawner{ "internal-dpl-aod-spawner", @@ -402,9 +402,8 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext {}, PluginManager::loadAlgorithmFromPlugin("O2FrameworkOnDemandTablesSupport", "ExtendedTableSpawner", ctx), // readers::AODReaderHelpers::aodSpawnerCallback(ctx), {}}; - AnalysisSupportHelpers::addMissingOutputsToSpawner({}, ac.spawnerInputs, ac.requestedAODs, aodSpawner); - - AnalysisSupportHelpers::addMissingOutputsToReader(ac.providedAODs, ac.requestedAODs, aodReader); + AnalysisSupportHelpers::addMissingOutputsToSpawner({}, dec.spawnerInputs, dec.requestedAODs, aodSpawner); + AnalysisSupportHelpers::addMissingOutputsToReader(dec.providedAODs, dec.requestedAODs, aodReader); std::sort(requestedCCDBs.begin(), requestedCCDBs.end(), inputSpecLessThan); std::sort(providedCCDBs.begin(), providedCCDBs.end(), outputSpecLessThan); @@ -547,7 +546,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext // This is to inject a file sink so that any dangling ATSK object is written // to a ROOT file. - if (ac.providedOutputObjHist.empty() == false) { + if (dec.providedOutputObjHist.empty() == false) { auto rootSink = AnalysisSupportHelpers::getOutputObjHistSink(ctx); extraSpecs.push_back(rootSink); } @@ -557,8 +556,8 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext /// Analyze all ouputs auto [outputsInputsTmp, isDanglingTmp] = analyzeOutputs(workflow); - ac.isDangling = isDanglingTmp; - ac.outputsInputs = outputsInputsTmp; + dec.isDangling = isDanglingTmp; + dec.outputsInputs = outputsInputsTmp; // create DataOutputDescriptor std::shared_ptr dod = AnalysisSupportHelpers::getDataOutputDirector(ctx); @@ -566,28 +565,28 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext // select outputs of type AOD which need to be saved // ATTENTION: if there are dangling outputs the getGlobalAODSink // has to be created in any case! - for (auto ii = 0u; ii < ac.outputsInputs.size(); ii++) { - if (DataSpecUtils::partialMatch(ac.outputsInputs[ii], extendedAODOrigins)) { - auto ds = dod->getDataOutputDescriptors(ac.outputsInputs[ii]); - if (ds.size() > 0 || ac.isDangling[ii]) { - ac.outputsInputsAOD.emplace_back(ac.outputsInputs[ii]); + for (auto ii = 0u; ii < dec.outputsInputs.size(); ii++) { + if (DataSpecUtils::partialMatch(dec.outputsInputs[ii], extendedAODOrigins)) { + auto ds = dod->getDataOutputDescriptors(dec.outputsInputs[ii]); + if (ds.size() > 0 || dec.isDangling[ii]) { + dec.outputsInputsAOD.emplace_back(dec.outputsInputs[ii]); } } } // file sink for any AOD output - if (ac.outputsInputsAOD.size() > 0) { + if (dec.outputsInputsAOD.size() > 0) { // add TFNumber and TFFilename as input to the writer - ac.outputsInputsAOD.emplace_back(InputSpec{"tfn", "TFN", "TFNumber"}); - ac.outputsInputsAOD.emplace_back(InputSpec{"tff", "TFF", "TFFilename"}); + dec.outputsInputsAOD.emplace_back(InputSpec{"tfn", "TFN", "TFNumber"}); + dec.outputsInputsAOD.emplace_back(InputSpec{"tff", "TFF", "TFFilename"}); auto fileSink = AnalysisSupportHelpers::getGlobalAODSink(ctx); extraSpecs.push_back(fileSink); - auto it = std::find_if(ac.outputsInputs.begin(), ac.outputsInputs.end(), [](InputSpec& spec) -> bool { + auto it = std::find_if(dec.outputsInputs.begin(), dec.outputsInputs.end(), [](InputSpec& spec) -> bool { return DataSpecUtils::partialMatch(spec, o2::header::DataOrigin("TFN")); }); - size_t ii = std::distance(ac.outputsInputs.begin(), it); - ac.isDangling[ii] = false; + size_t ii = std::distance(dec.outputsInputs.begin(), it); + dec.isDangling[ii] = false; } workflow.insert(workflow.end(), extraSpecs.begin(), extraSpecs.end()); @@ -595,20 +594,20 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext // Select dangling outputs which are not of type AOD std::vector redirectedOutputsInputs; - for (auto ii = 0u; ii < ac.outputsInputs.size(); ii++) { + for (auto ii = 0u; ii < dec.outputsInputs.size(); ii++) { if (ctx.options().get("forwarding-policy") == "none") { continue; } // We forward to the output proxy all the inputs only if they are dangling // or if the forwarding policy is "proxy". - if (!ac.isDangling[ii] && (ctx.options().get("forwarding-policy") != "all")) { + if (!dec.isDangling[ii] && (ctx.options().get("forwarding-policy") != "all")) { continue; } // AODs are skipped in any case. - if (DataSpecUtils::partialMatch(ac.outputsInputs[ii], extendedAODOrigins)) { + if (DataSpecUtils::partialMatch(dec.outputsInputs[ii], extendedAODOrigins)) { continue; } - redirectedOutputsInputs.emplace_back(ac.outputsInputs[ii]); + redirectedOutputsInputs.emplace_back(dec.outputsInputs[ii]); } std::vector unmatched; From 027cad2deaa056cd2bca7c465bd1f74309005ed1 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Tue, 2 Dec 2025 09:48:09 +0100 Subject: [PATCH 060/234] Propagate dangling edges context to init context and delay algo loading --- .../AnalysisSupport/src/AODReaderHelpers.cxx | 16 ++++---- .../AnalysisSupport/src/AODReaderHelpers.h | 4 +- Framework/Core/src/ArrowSupport.cxx | 20 ++++++---- Framework/Core/src/WorkflowHelpers.cxx | 38 +++++-------------- Framework/Core/src/runDataProcessing.cxx | 5 +++ 5 files changed, 37 insertions(+), 46 deletions(-) diff --git a/Framework/AnalysisSupport/src/AODReaderHelpers.cxx b/Framework/AnalysisSupport/src/AODReaderHelpers.cxx index 045ef072a3040..7f08dd0b36a64 100644 --- a/Framework/AnalysisSupport/src/AODReaderHelpers.cxx +++ b/Framework/AnalysisSupport/src/AODReaderHelpers.cxx @@ -79,12 +79,12 @@ struct Buildable { } // namespace -AlgorithmSpec AODReaderHelpers::indexBuilderCallback(ConfigContext const& ctx) +AlgorithmSpec AODReaderHelpers::indexBuilderCallback(ConfigContext const& /*ctx*/) { - auto& ac = ctx.services().get(); - return AlgorithmSpec::InitCallback{[requested = ac.requestedIDXs](InitContext& /*ic*/) { + return AlgorithmSpec::InitCallback{[](InitContext& ic) { + auto const& requested = ic.services().get().requestedIDXs; std::vector buildables; - for (auto& i : requested) { + for (auto const& i : requested) { buildables.emplace_back(i); } std::vector builders; @@ -181,12 +181,12 @@ struct Spawnable { } // namespace -AlgorithmSpec AODReaderHelpers::aodSpawnerCallback(ConfigContext const& ctx) +AlgorithmSpec AODReaderHelpers::aodSpawnerCallback(ConfigContext const& /*ctx*/) { - auto& ac = ctx.services().get(); - return AlgorithmSpec::InitCallback{[requested = ac.spawnerInputs](InitContext& /*ic*/) { + return AlgorithmSpec::InitCallback{[](InitContext& ic) { + auto const& requested = ic.services().get().spawnerInputs; std::vector spawnables; - for (auto& i : requested) { + for (auto const& i : requested) { spawnables.emplace_back(i); } std::vector spawners; diff --git a/Framework/AnalysisSupport/src/AODReaderHelpers.h b/Framework/AnalysisSupport/src/AODReaderHelpers.h index 197907ca3ccb1..848ef6b696713 100644 --- a/Framework/AnalysisSupport/src/AODReaderHelpers.h +++ b/Framework/AnalysisSupport/src/AODReaderHelpers.h @@ -20,8 +20,8 @@ namespace o2::framework::readers struct AODReaderHelpers { static AlgorithmSpec rootFileReaderCallback(); - static AlgorithmSpec aodSpawnerCallback(ConfigContext const& ctx); - static AlgorithmSpec indexBuilderCallback(ConfigContext const& ctx); + static AlgorithmSpec aodSpawnerCallback(ConfigContext const& /*ctx*/); + static AlgorithmSpec indexBuilderCallback(ConfigContext const& /*ctx*/); }; } // namespace o2::framework::readers diff --git a/Framework/Core/src/ArrowSupport.cxx b/Framework/Core/src/ArrowSupport.cxx index ee4275281ab31..c0280b144e146 100644 --- a/Framework/Core/src/ArrowSupport.cxx +++ b/Framework/Core/src/ArrowSupport.cxx @@ -13,6 +13,7 @@ #include "Framework/ArrowContext.h" #include "Framework/ArrowTableSlicingCache.h" #include "Framework/DataProcessor.h" +#include "Framework/CommonDataProcessors.h" #include "Framework/DataProcessingStats.h" #include "Framework/ServiceRegistry.h" #include "Framework/ConfigContext.h" @@ -609,9 +610,9 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() // recreate inputs and outputs builder->inputs.clear(); builder->outputs.clear(); - // replace AlgorithmSpec - // FIXME: it should be made more generic, so it does not need replacement... - builder->algorithm = PluginManager::loadAlgorithmFromPlugin("O2FrameworkOnDemandTablesSupport", "IndexTableBuilder", ctx); // readers::AODReaderHelpers::indexBuilderCallback(ctx); + + // load real AlgorithmSpec before deployment + builder->algorithm = PluginManager::loadAlgorithmFromPlugin("O2FrameworkOnDemandTablesSupport", "IndexTableBuilder", ctx); AnalysisSupportHelpers::addMissingOutputsToBuilder(dec.requestedIDXs, dec.requestedAODs, dec.requestedDYNs, *builder); } @@ -634,10 +635,10 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() // recreate inputs and outputs spawner->outputs.clear(); spawner->inputs.clear(); - AnalysisSupportHelpers::addMissingOutputsToSpawner({}, dec.spawnerInputs, dec.requestedAODs, *spawner); - // replace AlgorithmSpec - // FIXME: it should be made more generic, so it does not need replacement... + + // load real AlgorithmSpec before deployment spawner->algorithm = PluginManager::loadAlgorithmFromPlugin("O2FrameworkOnDemandTablesSupport", "ExtendedTableSpawner", ctx); + AnalysisSupportHelpers::addMissingOutputsToSpawner({}, dec.spawnerInputs, dec.requestedAODs, *spawner); } if (analysisCCDB != workflow.end()) { @@ -654,8 +655,7 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() // recreate inputs and outputs analysisCCDB->outputs.clear(); analysisCCDB->inputs.clear(); - // replace AlgorithmSpec - // FIXME: it should be made more generic, so it does not need replacement... + // load real AlgorithmSpec before deployment // FIXME how can I make the lookup depend on DYN tables as well?? analysisCCDB->algorithm = PluginManager::loadAlgorithmFromPlugin("O2FrameworkCCDBSupport", "AnalysisCCDBFetcherPlugin", ctx); AnalysisSupportHelpers::addMissingOutputsToBuilder(dec.analysisCCDBInputs, dec.requestedAODs, dec.requestedDYNs, *analysisCCDB); @@ -682,6 +682,10 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() if (reader->outputs.empty()) { // nothing to read workflow.erase(reader); + } else { + // load reader algorithm before deployment + auto&& algo = PluginManager::loadAlgorithmFromPlugin("O2FrameworkAnalysisSupport", "ROOTFileReader", ctx); + reader->algorithm = CommonDataProcessors::wrapWithTimesliceConsumption(algo); } } diff --git a/Framework/Core/src/WorkflowHelpers.cxx b/Framework/Core/src/WorkflowHelpers.cxx index fdcdb6093a111..fd9099e1aa24e 100644 --- a/Framework/Core/src/WorkflowHelpers.cxx +++ b/Framework/Core/src/WorkflowHelpers.cxx @@ -156,6 +156,7 @@ int defaultConditionQueryRateMultiplier() void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext& ctx) { + int rateLimitingIPCID = std::stoi(ctx.options().get("timeframes-rate-limit-ipcid")); DataProcessorSpec ccdbBackend{ .name = "internal-dpl-ccdb-backend", .outputs = {}, @@ -230,23 +231,6 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext ConfigParamSpec{"step-value-enumeration", VariantType::Int64, 1ll, {"step between one value and the other"}}}, .requiredServices = CommonServices::defaultServices("O2FrameworkAnalysisSupport:RunSummary")}; - // AOD reader can be rate limited - int rateLimitingIPCID = std::stoi(ctx.options().get("timeframes-rate-limit-ipcid")); - std::string rateLimitingChannelConfigInput; - std::string rateLimitingChannelConfigOutput; - bool internalRateLimiting = false; - - // In case we have rate-limiting requested, any device without an input will get one on the special - // "DPL/RATE" message. - if (rateLimitingIPCID >= 0) { - rateLimitingChannelConfigInput = fmt::format("name=metric-feedback,type=pull,method=connect,address=ipc://{}metric-feedback-{},transport=shmem,rateLogging=0", - ChannelSpecHelpers::defaultIPCFolder(), rateLimitingIPCID); - rateLimitingChannelConfigOutput = fmt::format("name=metric-feedback,type=push,method=bind,address=ipc://{}metric-feedback-{},transport=shmem,rateLogging=0", - ChannelSpecHelpers::defaultIPCFolder(), rateLimitingIPCID); - internalRateLimiting = true; - aodReader.options.emplace_back(ConfigParamSpec{"channel-config", VariantType::String, rateLimitingChannelConfigInput, {"how many timeframes can be in flight at the same time"}}); - } - ctx.services().registerService(ServiceRegistryHelpers::handleForService(new DanglingEdgesContext)); auto& dec = ctx.services().get(); @@ -274,7 +258,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext // A timeframeSink consumes timeframes without creating new // timeframe data. bool timeframeSink = hasTimeframeInputs && !hasTimeframeOutputs; - if (std::stoi(ctx.options().get("timeframes-rate-limit-ipcid")) != -1) { + if (rateLimitingIPCID != -1) { if (timeframeSink && processor.name.find("internal-dpl-injected-dummy-sink") == std::string::npos) { O2_SIGNPOST_ID_GENERATE(sid, workflow_helpers); uint32_t hash = runtime_hash(processor.name.c_str()); @@ -384,7 +368,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext "internal-dpl-aod-index-builder", {}, {}, - PluginManager::loadAlgorithmFromPlugin("O2FrameworkOnDemandTablesSupport", "IndexTableBuilder", ctx), // readers::AODReaderHelpers::indexBuilderCallback(ctx), + AlgorithmSpec::dummyAlgorithm(), // real algorithm will be set in adjustTopology {}}; AnalysisSupportHelpers::addMissingOutputsToBuilder(dec.requestedIDXs, dec.requestedAODs, dec.requestedDYNs, indexBuilder); @@ -400,7 +384,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext "internal-dpl-aod-spawner", {}, {}, - PluginManager::loadAlgorithmFromPlugin("O2FrameworkOnDemandTablesSupport", "ExtendedTableSpawner", ctx), // readers::AODReaderHelpers::aodSpawnerCallback(ctx), + AlgorithmSpec::dummyAlgorithm(), // real algorithm will be set in adjustTopology {}}; AnalysisSupportHelpers::addMissingOutputsToSpawner({}, dec.spawnerInputs, dec.requestedAODs, aodSpawner); AnalysisSupportHelpers::addMissingOutputsToReader(dec.providedAODs, dec.requestedAODs, aodReader); @@ -431,13 +415,11 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext auto mctracks2aod = std::find_if(workflow.begin(), workflow.end(), [](auto const& x) { return x.name == "mctracks-to-aod"; }); if (mctracks2aod == workflow.end()) { // add normal reader - auto&& algo = PluginManager::loadAlgorithmFromPlugin("O2FrameworkAnalysisSupport", "ROOTFileReader", ctx); - aodReader.algorithm = CommonDataProcessors::wrapWithTimesliceConsumption(algo); aodReader.outputs.emplace_back(OutputSpec{"TFN", "TFNumber"}); aodReader.outputs.emplace_back(OutputSpec{"TFF", "TFFilename"}); } else { - // AODs are being injected on-the-fly, add dummy reader - auto algo = AlgorithmSpec{ + // AODs are being injected on-the-fly, add error-handler reader + aodReader.algorithm = AlgorithmSpec{ adaptStateful( [outputs = aodReader.outputs](DeviceSpec const&) { LOGP(warn, "Workflow with injected AODs has unsatisfied inputs:"); @@ -448,7 +430,6 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext // to ensure the output type for adaptStateful return adaptStateless([](DataAllocator&) {}); })}; - aodReader.algorithm = CommonDataProcessors::wrapWithTimesliceConsumption(algo); } auto concrete = DataSpecUtils::asConcreteDataMatcher(aodReader.inputs[0]); timer.outputs.emplace_back(concrete.origin, concrete.description, concrete.subSpec, Lifetime::Enumeration); @@ -533,9 +514,6 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext // add the Analysys CCDB backend which reads CCDB objects using a provided table if (analysisCCDBBackend.outputs.empty() == false) { - // add normal reader - auto&& algo = PluginManager::loadAlgorithmFromPlugin("O2FrameworkCCDBSupport", "AnalysisCCDBFetcherPlugin", ctx); - analysisCCDBBackend.algorithm = algo; extraSpecs.push_back(analysisCCDBBackend); } @@ -637,6 +615,10 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext extraSpecs.push_back(CommonDataProcessors::getScheduledDummySink(ignored)); } else { O2_SIGNPOST_EVENT_EMIT(workflow_helpers, sid, "injectServiceDevices", "Injecting rate limited dummy sink"); + std::string rateLimitingChannelConfigOutput; + if (rateLimitingIPCID != -1) { + rateLimitingChannelConfigOutput = fmt::format("name=metric-feedback,type=push,method=bind,address=ipc://{}metric-feedback-{},transport=shmem,rateLogging=0", ChannelSpecHelpers::defaultIPCFolder(), rateLimitingIPCID); + } extraSpecs.push_back(CommonDataProcessors::getDummySink(ignored, rateLimitingChannelConfigOutput)); } } diff --git a/Framework/Core/src/runDataProcessing.cxx b/Framework/Core/src/runDataProcessing.cxx index c36b1deadeefb..14bdb2d8c72d9 100644 --- a/Framework/Core/src/runDataProcessing.cxx +++ b/Framework/Core/src/runDataProcessing.cxx @@ -9,6 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include +#include "Framework/DanglingEdgesContext.h" #include "Framework/TopologyPolicyHelpers.h" #define BOOST_BIND_GLOBAL_PLACEHOLDERS #include @@ -1016,6 +1017,7 @@ void doDefaultWorkflowTerminationHook() } int doChild(int argc, char** argv, ServiceRegistry& serviceRegistry, + DanglingEdgesContext& danglingEdgesContext, RunningWorkflowInfo const& runningWorkflow, RunningDeviceRef ref, DriverConfig const& driverConfig, @@ -1078,6 +1080,7 @@ int doChild(int argc, char** argv, ServiceRegistry& serviceRegistry, &spec, "aEvaluator, &serviceRegistry, + &danglingEdgesContext, &deviceState, &deviceProxy, &processingPolicies, @@ -1101,6 +1104,7 @@ int doChild(int argc, char** argv, ServiceRegistry& serviceRegistry, serviceRef.registerService(ServiceRegistryHelpers::handleForService(&runningWorkflow)); serviceRef.registerService(ServiceRegistryHelpers::handleForService(deviceContext.get())); serviceRef.registerService(ServiceRegistryHelpers::handleForService(&driverConfig)); + serviceRef.registerService(ServiceRegistryHelpers::handleForService(&danglingEdgesContext)); auto device = std::make_unique(ref, serviceRegistry); @@ -1953,6 +1957,7 @@ int runStateMachine(DataProcessorSpecs const& workflow, if (runningWorkflow.devices[di].id == frameworkId) { return doChild(driverInfo.argc, driverInfo.argv, serviceRegistry, + driverInfo.configContext->services().get(), runningWorkflow, ref, driverConfig, driverInfo.processingPolicies, From 91a991f6baa4c002180612a7586edfa302ff940b Mon Sep 17 00:00:00 2001 From: Piotr Konopka Date: Tue, 16 Dec 2025 16:42:24 +0100 Subject: [PATCH 061/234] DPL: allow to disable oldest possible timeframe propagation with a label This allows to disable all DomainInfoHeader propagation with a corresponding DataProcessorLabel. It addresses the issue reported in QC-1320, where remote QC workflows were getting flooded with a DIH for each QC task instance in the setup. --- Framework/Core/CMakeLists.txt | 1 + .../Core/include/Framework/CommonLabels.h | 26 +++++++++++++++++++ Framework/Core/src/CommonLabels.cxx | 19 ++++++++++++++ Framework/Core/src/CommonServices.cxx | 7 +++++ Framework/Core/src/DataProcessingHelpers.cxx | 7 +++++ Framework/Core/src/DecongestionService.h | 2 ++ 6 files changed, 62 insertions(+) create mode 100644 Framework/Core/include/Framework/CommonLabels.h create mode 100644 Framework/Core/src/CommonLabels.cxx diff --git a/Framework/Core/CMakeLists.txt b/Framework/Core/CMakeLists.txt index fe8a91eaa0449..1daba5dbc9798 100644 --- a/Framework/Core/CMakeLists.txt +++ b/Framework/Core/CMakeLists.txt @@ -108,6 +108,7 @@ o2_add_library(Framework src/SimpleOptionsRetriever.cxx src/O2ControlHelpers.cxx src/O2ControlLabels.cxx + src/CommonLabels.cxx src/O2ControlParameters.cxx src/O2DataModelHelpers.cxx src/OutputSpec.cxx diff --git a/Framework/Core/include/Framework/CommonLabels.h b/Framework/Core/include/Framework/CommonLabels.h new file mode 100644 index 0000000000000..8be41a33af41d --- /dev/null +++ b/Framework/Core/include/Framework/CommonLabels.h @@ -0,0 +1,26 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FRAMEWORK_COMMONLABELS_H +#define O2_FRAMEWORK_COMMONLABELS_H + +#include "Framework/DataProcessorLabel.h" + +namespace o2::framework +{ + +// Label to disable forwarding/advertising of DomainInfoHeader (oldest possible outputs) +// When present on a DataProcessor, no DomainInfoHeader messages will be sent downstream. +const extern DataProcessorLabel suppressDomainInfoLabel; + +} // namespace o2::framework + +#endif // O2_FRAMEWORK_COMMONLABELS_H diff --git a/Framework/Core/src/CommonLabels.cxx b/Framework/Core/src/CommonLabels.cxx new file mode 100644 index 0000000000000..f728e194f611b --- /dev/null +++ b/Framework/Core/src/CommonLabels.cxx @@ -0,0 +1,19 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/CommonLabels.h" + +namespace o2::framework +{ + +const DataProcessorLabel suppressDomainInfoLabel = {"suppress-domain-info"}; + +} // namespace o2::framework diff --git a/Framework/Core/src/CommonServices.cxx b/Framework/Core/src/CommonServices.cxx index 3aa46269bdd7e..f786d99fd2c0d 100644 --- a/Framework/Core/src/CommonServices.cxx +++ b/Framework/Core/src/CommonServices.cxx @@ -45,6 +45,7 @@ #include "Framework/DefaultsHelpers.h" #include "Framework/Signpost.h" #include "Framework/DriverConfig.h" +#include "Framework/CommonLabels.h" #include "TextDriverClient.h" #include "WSDriverClient.h" @@ -604,6 +605,12 @@ o2::framework::ServiceSpec break; } } + for (const auto& label : services.get().labels) { + if (label == suppressDomainInfoLabel) { + decongestion->suppressDomainInfo = true; + break; + } + } auto& queue = services.get(); decongestion->oldestPossibleTimesliceTask = AsyncQueueHelpers::create(queue, {.name = "oldest-possible-timeslice", .score = 100}); return ServiceHandle{TypeIdHelpers::uniqueId(), decongestion, ServiceKind::Serial}; diff --git a/Framework/Core/src/DataProcessingHelpers.cxx b/Framework/Core/src/DataProcessingHelpers.cxx index 9c53bbf8b2c10..aea682a8d00c3 100644 --- a/Framework/Core/src/DataProcessingHelpers.cxx +++ b/Framework/Core/src/DataProcessingHelpers.cxx @@ -34,6 +34,7 @@ #include "Framework/DeviceStateEnums.h" #include "Headers/DataHeader.h" #include "Framework/DataProcessingHeader.h" +#include "DecongestionService.h" #include #include @@ -83,6 +84,9 @@ void doSendOldestPossibleTimeframe(ServiceRegistryRef ref, fair::mq::TransportFa bool DataProcessingHelpers::sendOldestPossibleTimeframe(ServiceRegistryRef const& ref, ForwardChannelInfo const& info, ForwardChannelState& state, size_t timeslice) { + if (ref.get().suppressDomainInfo) { + return false; + } if (state.oldestForChannel.value >= timeslice) { return false; } @@ -93,6 +97,9 @@ bool DataProcessingHelpers::sendOldestPossibleTimeframe(ServiceRegistryRef const bool DataProcessingHelpers::sendOldestPossibleTimeframe(ServiceRegistryRef const& ref, OutputChannelInfo const& info, OutputChannelState& state, size_t timeslice) { + if (ref.get().suppressDomainInfo) { + return false; + } if (state.oldestForChannel.value >= timeslice) { return false; } diff --git a/Framework/Core/src/DecongestionService.h b/Framework/Core/src/DecongestionService.h index c45e9a36217ec..1a42d3577bc0a 100644 --- a/Framework/Core/src/DecongestionService.h +++ b/Framework/Core/src/DecongestionService.h @@ -18,6 +18,8 @@ namespace o2::framework struct DecongestionService { /// Wether we are a source in the processing chain bool isFirstInTopology = true; + /// do not advertise/forward DomainInfoHeader from this device + bool suppressDomainInfo = false; /// The last timeslice which the ExpirationHandler::Creator callback /// created. This can be used to skip dummy iterations. size_t nextEnumerationTimeslice = 0; From 9bbf6ecca2da073db51497ab83d380e4cff355e5 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 7 Jan 2026 10:53:36 +0100 Subject: [PATCH 062/234] DPL: more refactoring of the forwarding code Use a single helper function to improve readability. --- .../include/Framework/DataProcessingHelpers.h | 5 +- Framework/Core/src/DataProcessingDevice.cxx | 6 +- Framework/Core/src/DataProcessingHelpers.cxx | 158 +++++++----------- Framework/Core/test/test_ForwardInputs.cxx | 62 ++----- 4 files changed, 84 insertions(+), 147 deletions(-) diff --git a/Framework/Core/include/Framework/DataProcessingHelpers.h b/Framework/Core/include/Framework/DataProcessingHelpers.h index be02aae5d2f69..34bb87613d920 100644 --- a/Framework/Core/include/Framework/DataProcessingHelpers.h +++ b/Framework/Core/include/Framework/DataProcessingHelpers.h @@ -53,8 +53,9 @@ struct DataProcessingHelpers { /// starts the EoS timers and returns the new TransitionHandlingState in case as new state is requested static TransitionHandlingState updateStateTransition(ServiceRegistryRef const& ref, ProcessingPolicies const& policies); /// Helper to route messages for forwarding - static std::vector routeForwardedMessages(FairMQDeviceProxy& proxy, TimesliceSlot slot, std::vector& currentSetOfInputs, - TimesliceIndex::OldestOutputInfo oldestTimeslice, bool copy, bool consume); + static std::vector routeForwardedMessages(FairMQDeviceProxy& proxy, + std::vector& currentSetOfInputs, + const bool copyByDefault, bool consume); }; } // namespace o2::framework #endif // O2_FRAMEWORK_DATAPROCESSINGHELPERS_H_ diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index 40f1061e60332..63c333561f24e 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -588,10 +588,12 @@ auto decongestionCallbackLate = [](AsyncTask& task, size_t aid) -> void { static auto forwardInputs = [](ServiceRegistryRef registry, TimesliceSlot slot, std::vector& currentSetOfInputs, TimesliceIndex::OldestOutputInfo oldestTimeslice, bool copy, bool consume = true) { auto& proxy = registry.get(); - auto forwardedParts = DataProcessingHelpers::routeForwardedMessages(proxy, slot, currentSetOfInputs, oldestTimeslice, copy, consume); O2_SIGNPOST_ID_GENERATE(sid, forwarding); - O2_SIGNPOST_EVENT_EMIT(forwarding, sid, "forwardInputs", "Forwarding %zu messages", forwardedParts.size()); + O2_SIGNPOST_START(forwarding, sid, "forwardInputs", "Starting forwarding for slot %zu with oldestTimeslice %zu %{public}s%{public}s%{public}s", + slot.index, oldestTimeslice.timeslice.value, copy ? "with copy" : "", copy && consume ? " and " : "", consume ? "with consume" : ""); + auto forwardedParts = DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copy, consume); + for (int fi = 0; fi < proxy.getNumForwardChannels(); fi++) { if (forwardedParts[fi].Size() == 0) { continue; diff --git a/Framework/Core/src/DataProcessingHelpers.cxx b/Framework/Core/src/DataProcessingHelpers.cxx index aea682a8d00c3..76730e9edab4e 100644 --- a/Framework/Core/src/DataProcessingHelpers.cxx +++ b/Framework/Core/src/DataProcessingHelpers.cxx @@ -228,129 +228,99 @@ TransitionHandlingState DataProcessingHelpers::updateStateTransition(ServiceRegi } } -static auto toBeForwardedHeader = [](void* header) -> bool { - // If is now possible that the record is not complete when - // we forward it, because of a custom completion policy. - // this means that we need to skip the empty entries in the - // record for being forwarded. - if (header == nullptr) { - return false; - } - auto dh = o2::header::get(header); - if (!dh) { - return false; - } - bool retval = !o2::header::get(header) && - !o2::header::get(header) && - o2::header::get(header); - // DataHeader is there. Complain if we have unexpected headers present / missing - if (!retval) { - LOGP(error, "Dropping data because of malformed header structure"); - } - return retval; -}; - -static auto toBeforwardedMessageSet = [](std::vector& cachedForwardingChoices, - FairMQDeviceProxy& proxy, - std::unique_ptr& header, - std::unique_ptr& payload, - size_t total, - bool consume) { - if (header.get() == nullptr) { - // Missing an header is not an error anymore. - // it simply means that we did not receive the - // given input, but we were asked to - // consume existing, so we skip it. - return false; - } - if (payload.get() == nullptr && consume == true) { - // If the payload is not there, it means we already - // processed it with ConsumeExisiting. Therefore we - // need to do something only if this is the last consume. - header.reset(nullptr); - return false; - } - - auto fdph = o2::header::get(header->GetData()); - if (fdph == nullptr) { - LOG(error) << "Data is missing DataProcessingHeader"; - return false; - } - auto fdh = o2::header::get(header->GetData()); - if (fdh == nullptr) { - LOG(error) << "Data is missing DataHeader"; - return false; - } - - // We need to find the forward route only for the first - // part of a split payload. All the others will use the same. - // but always check if we have a sequence of multiple payloads - if (fdh->splitPayloadIndex == 0 || fdh->splitPayloadParts <= 1 || total > 1) { - proxy.getMatchingForwardChannelIndexes(cachedForwardingChoices, *fdh, fdph->startTime); - } - return cachedForwardingChoices.empty() == false; -}; - -std::vector DataProcessingHelpers::routeForwardedMessages(FairMQDeviceProxy& proxy, TimesliceSlot slot, std::vector& currentSetOfInputs, - TimesliceIndex::OldestOutputInfo oldestTimeslice, bool copy, bool consume) +auto DataProcessingHelpers::routeForwardedMessages(FairMQDeviceProxy& proxy, + std::vector& currentSetOfInputs, + const bool copyByDefault, bool consume) -> std::vector { // we collect all messages per forward in a map and send them together std::vector forwardedParts; forwardedParts.resize(proxy.getNumForwards()); - std::vector cachedForwardingChoices{}; + std::vector forwardingChoices{}; O2_SIGNPOST_ID_GENERATE(sid, forwarding); - O2_SIGNPOST_START(forwarding, sid, "forwardInputs", "Starting forwarding for slot %zu with oldestTimeslice %zu %{public}s%{public}s%{public}s", - slot.index, oldestTimeslice.timeslice.value, copy ? "with copy" : "", copy && consume ? " and " : "", consume ? "with consume" : ""); for (size_t ii = 0, ie = currentSetOfInputs.size(); ii < ie; ++ii) { auto& messageSet = currentSetOfInputs[ii]; - // In case the messageSet is empty, there is nothing to be done. - if (messageSet.size() == 0) { - continue; - } - if (!toBeForwardedHeader(messageSet.header(0)->GetData())) { - continue; - } - cachedForwardingChoices.clear(); + forwardingChoices.clear(); - for (size_t pi = 0; pi < currentSetOfInputs[ii].size(); ++pi) { - auto& messageSet = currentSetOfInputs[ii]; + for (size_t pi = 0; pi < messageSet.size(); ++pi) { auto& header = messageSet.header(pi); + + // If is now possible that the record is not complete when + // we forward it, because of a custom completion policy. + // this means that we need to skip the empty entries in the + // record for being forwarded. + if (header->GetData() == nullptr) { + continue; + } + auto dih = o2::header::get(header->GetData()); + if (dih) { + continue; + } + auto sih = o2::header::get(header->GetData()); + if (sih) { + continue; + } + + auto dph = o2::header::get(header->GetData()); + auto dh = o2::header::get(header->GetData()); + + if (dph == nullptr || dh == nullptr) { + // Complain only if this is not an out-of-band message + LOGP(error, "Data is missing {}{}{}", + dph ? "DataProcessingHeader" : "", dph || dh ? "and" : "", dh ? "DataHeader" : ""); + continue; + } + auto& payload = messageSet.payload(pi); - auto total = messageSet.getNumberOfPayloads(pi); - if (!toBeforwardedMessageSet(cachedForwardingChoices, proxy, header, payload, total, consume)) { + if (payload.get() == nullptr && consume == true) { + // If the payload is not there, it means we already + // processed it with ConsumeExisiting. Therefore we + // need to do something only if this is the last consume. + header.reset(nullptr); continue; } - // In case of more than one forward route, we need to copy the message. - // This will eventually use the same mamory if running with the same backend. - if (cachedForwardingChoices.size() > 1) { - copy = true; + // We need to find the forward route only for the first + // part of a split payload. All the others will use the same. + // Therefore, we reset and recompute the forwarding choice: + // + // - If this is the first payload of a [header0][payload0][header0][payload1] sequence, + // which is actually always created and handled together + // - If the message is not a multipart (splitPayloadParts 0) or has only one part + // - If it's a message of the kind [header0][payload1][payload2][payload3]... and therefore + // we will already use the same choice in the for loop below. + if (dh->splitPayloadIndex == 0 || dh->splitPayloadParts <= 1 || messageSet.getNumberOfPayloads(pi) > 0) { + proxy.getMatchingForwardChannelIndexes(forwardingChoices, *dh, dph->startTime); } - auto* dh = o2::header::get(header->GetData()); - auto* dph = o2::header::get(header->GetData()); - if (copy) { - for (auto& cachedForwardingChoice : cachedForwardingChoices) { + if (forwardingChoices.empty()) { + // Nothing to forward go to the next messageset + continue; + } + + // In case of more than one forward route, we need to copy the message. + // This will eventually use the same memory if running with the same backend. + if (copyByDefault || forwardingChoices.size() > 1) { + for (auto& choice : forwardingChoices) { auto&& newHeader = header->GetTransport()->CreateMessage(); O2_SIGNPOST_EVENT_EMIT(forwarding, sid, "forwardInputs", "Forwarding a copy of %{public}s to route %d.", - fmt::format("{}/{}/{}@timeslice:{} tfCounter:{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification, dph->startTime, dh->tfCounter).c_str(), cachedForwardingChoice.value); + fmt::format("{}/{}/{}@timeslice:{} tfCounter:{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification, dph->startTime, dh->tfCounter).c_str(), choice.value); newHeader->Copy(*header); - forwardedParts[cachedForwardingChoice.value].AddPart(std::move(newHeader)); + forwardedParts[choice.value].AddPart(std::move(newHeader)); for (size_t payloadIndex = 0; payloadIndex < messageSet.getNumberOfPayloads(pi); ++payloadIndex) { auto&& newPayload = header->GetTransport()->CreateMessage(); newPayload->Copy(*messageSet.payload(pi, payloadIndex)); - forwardedParts[cachedForwardingChoice.value].AddPart(std::move(newPayload)); + forwardedParts[choice.value].AddPart(std::move(newPayload)); } } } else { O2_SIGNPOST_EVENT_EMIT(forwarding, sid, "forwardInputs", "Forwarding %{public}s to route %d.", - fmt::format("{}/{}/{}@timeslice:{} tfCounter:{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification, dph->startTime, dh->tfCounter).c_str(), cachedForwardingChoices.back().value); - forwardedParts[cachedForwardingChoices.back().value].AddPart(std::move(messageSet.header(pi))); + fmt::format("{}/{}/{}@timeslice:{} tfCounter:{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification, dph->startTime, dh->tfCounter).c_str(), forwardingChoices.back().value); + forwardedParts[forwardingChoices.back().value].AddPart(std::move(messageSet.header(pi))); for (size_t payloadIndex = 0; payloadIndex < messageSet.getNumberOfPayloads(pi); ++payloadIndex) { - forwardedParts[cachedForwardingChoices.back().value].AddPart(std::move(messageSet.payload(pi, payloadIndex))); + forwardedParts[forwardingChoices.back().value].AddPart(std::move(messageSet.payload(pi, payloadIndex))); } } } diff --git a/Framework/Core/test/test_ForwardInputs.cxx b/Framework/Core/test/test_ForwardInputs.cxx index b1f42fb0398ca..5add90ec8f18e 100644 --- a/Framework/Core/test/test_ForwardInputs.cxx +++ b/Framework/Core/test/test_ForwardInputs.cxx @@ -15,8 +15,6 @@ #include "Framework/DataProcessingHelpers.h" #include "Framework/SourceInfoHeader.h" #include "Framework/DomainInfoHeader.h" -#include "Framework/ServiceRegistry.h" -#include "Framework/ServiceRegistryRef.h" #include "Framework/Signpost.h" #include "Framework/MessageSet.h" #include "Framework/FairMQDeviceProxy.h" @@ -45,11 +43,9 @@ TEST_CASE("ForwardInputsEmpty") bool copyByDefault = true; FairMQDeviceProxy proxy; - TimesliceIndex::OldestOutputInfo oldestTimeslice{.timeslice = {1}}; std::vector currentSetOfInputs; - TimesliceSlot slot{0}; - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, slot, currentSetOfInputs, oldestTimeslice, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.empty()); } @@ -88,7 +84,6 @@ TEST_CASE("ForwardInputsSingleMessageSingleRoute") proxy.bind({}, {}, routes, findChannelByName, nullptr); - TimesliceIndex::OldestOutputInfo oldestTimeslice{.timeslice = {0}}; std::vector currentSetOfInputs; MessageSet messageSet; @@ -100,9 +95,7 @@ TEST_CASE("ForwardInputsSingleMessageSingleRoute") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - TimesliceSlot slot{0}; - - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, slot, currentSetOfInputs, oldestTimeslice, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 1); // One route REQUIRE(result[0].Size() == 2); // Two messages for that route } @@ -141,7 +134,6 @@ TEST_CASE("ForwardInputsSingleMessageSingleRouteNoConsume") proxy.bind({}, {}, routes, findChannelByName, nullptr); - TimesliceIndex::OldestOutputInfo oldestTimeslice{.timeslice = {0}}; std::vector currentSetOfInputs; MessageSet messageSet; @@ -154,9 +146,7 @@ TEST_CASE("ForwardInputsSingleMessageSingleRouteNoConsume") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - TimesliceSlot slot{0}; - - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, slot, currentSetOfInputs, oldestTimeslice, copyByDefault, true); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, true); REQUIRE(result.size() == 1); REQUIRE(result[0].Size() == 0); // Because there is a nullptr, we do not forward this as it was already consumed. } @@ -199,7 +189,6 @@ TEST_CASE("ForwardInputsSingleMessageSingleRouteAtEOS") proxy.bind({}, {}, routes, findChannelByName, nullptr); - TimesliceIndex::OldestOutputInfo oldestTimeslice{.timeslice = {0}}; std::vector currentSetOfInputs; MessageSet messageSet; @@ -212,11 +201,10 @@ TEST_CASE("ForwardInputsSingleMessageSingleRouteAtEOS") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - TimesliceSlot slot{0}; - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, slot, currentSetOfInputs, oldestTimeslice, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 1); // One route - REQUIRE(result[0].Size() == 0); // FIXME: this is an actual error. It should be 2 + REQUIRE(result[0].Size() == 0); // FIXME: this is an actual error. It should be 2. However it cannot really happen. // Correct behavior below: // REQUIRE(result[0].Size() == 2); // REQUIRE(o2::header::get(result[0].At(0)->GetData()) == nullptr); @@ -260,7 +248,6 @@ TEST_CASE("ForwardInputsSingleMessageSingleRouteWithOldestPossible") proxy.bind({}, {}, routes, findChannelByName, nullptr); - TimesliceIndex::OldestOutputInfo oldestTimeslice{.timeslice = {0}}; std::vector currentSetOfInputs; MessageSet messageSet; @@ -273,9 +260,7 @@ TEST_CASE("ForwardInputsSingleMessageSingleRouteWithOldestPossible") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - TimesliceSlot slot{0}; - - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, slot, currentSetOfInputs, oldestTimeslice, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 1); // One route REQUIRE(result[0].Size() == 0); // FIXME: this is actually wrong // FIXME: actually correct behavior below @@ -329,7 +314,6 @@ TEST_CASE("ForwardInputsSingleMessageMultipleRoutes") proxy.bind({}, {}, routes, findChannelByName, nullptr); - TimesliceIndex::OldestOutputInfo oldestTimeslice{.timeslice = {0}}; std::vector currentSetOfInputs; MessageSet messageSet; @@ -341,9 +325,7 @@ TEST_CASE("ForwardInputsSingleMessageMultipleRoutes") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - TimesliceSlot slot{0}; - - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, slot, currentSetOfInputs, oldestTimeslice, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 2); // Two routes REQUIRE(result[0].Size() == 2); // Two messages per route REQUIRE(result[1].Size() == 0); // Only the first DPL matched channel matters @@ -395,7 +377,6 @@ TEST_CASE("ForwardInputsSingleMessageMultipleRoutesExternals") proxy.bind({}, {}, routes, findChannelByName, nullptr); - TimesliceIndex::OldestOutputInfo oldestTimeslice{.timeslice = {0}}; std::vector currentSetOfInputs; MessageSet messageSet; @@ -407,9 +388,7 @@ TEST_CASE("ForwardInputsSingleMessageMultipleRoutesExternals") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - TimesliceSlot slot{0}; - - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, slot, currentSetOfInputs, oldestTimeslice, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 2); // Two routes REQUIRE(result[0].Size() == 2); // With external matching channels, we need to copy and then forward REQUIRE(result[1].Size() == 2); // @@ -468,7 +447,6 @@ TEST_CASE("ForwardInputsMultiMessageMultipleRoutes") proxy.bind({}, {}, routes, findChannelByName, nullptr); - TimesliceIndex::OldestOutputInfo oldestTimeslice{.timeslice = {0}}; std::vector currentSetOfInputs; auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq"); @@ -488,9 +466,7 @@ TEST_CASE("ForwardInputsMultiMessageMultipleRoutes") currentSetOfInputs.emplace_back(std::move(messageSet2)); REQUIRE(currentSetOfInputs.size() == 2); - TimesliceSlot slot{0}; - - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, slot, currentSetOfInputs, oldestTimeslice, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 2); // Two routes REQUIRE(result[0].Size() == 2); // REQUIRE(result[1].Size() == 2); // @@ -542,7 +518,6 @@ TEST_CASE("ForwardInputsSingleMessageMultipleRoutesOnlyOneMatches") proxy.bind({}, {}, routes, findChannelByName, nullptr); - TimesliceIndex::OldestOutputInfo oldestTimeslice{.timeslice = {0}}; std::vector currentSetOfInputs; MessageSet messageSet; @@ -554,9 +529,7 @@ TEST_CASE("ForwardInputsSingleMessageMultipleRoutesOnlyOneMatches") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - TimesliceSlot slot{0}; - - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, slot, currentSetOfInputs, oldestTimeslice, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 2); // Two routes REQUIRE(result[0].Size() == 0); // Two messages per route REQUIRE(result[1].Size() == 2); // Two messages per route @@ -615,7 +588,6 @@ TEST_CASE("ForwardInputsSplitPayload") proxy.bind({}, {}, routes, findChannelByName, nullptr); - TimesliceIndex::OldestOutputInfo oldestTimeslice{.timeslice = {0}}; std::vector currentSetOfInputs; MessageSet messageSet; @@ -639,9 +611,7 @@ TEST_CASE("ForwardInputsSplitPayload") REQUIRE(messageSet.size() == 2); currentSetOfInputs.emplace_back(std::move(messageSet)); - TimesliceSlot slot{0}; - - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, slot, currentSetOfInputs, oldestTimeslice, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 2); // Two routes CHECK(result[0].Size() == 2); // No messages on this route CHECK(result[1].Size() == 5); // FIXME: Multipart matching has side effects also for the elements @@ -677,7 +647,6 @@ TEST_CASE("ForwardInputEOSSingleRoute") proxy.bind({}, {}, routes, findChannelByName, nullptr); - TimesliceIndex::OldestOutputInfo oldestTimeslice{.timeslice = {0}}; std::vector currentSetOfInputs; MessageSet messageSet; @@ -689,9 +658,7 @@ TEST_CASE("ForwardInputEOSSingleRoute") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - TimesliceSlot slot{0}; - - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, slot, currentSetOfInputs, oldestTimeslice, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 1); // One route REQUIRE(result[0].Size() == 0); // Oldest possible timeframe should not be forwarded } @@ -725,7 +692,6 @@ TEST_CASE("ForwardInputOldestPossibleSingleRoute") proxy.bind({}, {}, routes, findChannelByName, nullptr); - TimesliceIndex::OldestOutputInfo oldestTimeslice{.timeslice = {0}}; std::vector currentSetOfInputs; MessageSet messageSet; @@ -737,9 +703,7 @@ TEST_CASE("ForwardInputOldestPossibleSingleRoute") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - TimesliceSlot slot{0}; - - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, slot, currentSetOfInputs, oldestTimeslice, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 1); // One route REQUIRE(result[0].Size() == 0); // Oldest possible timeframe should not be forwarded } From 0e958cabd29f9dd6cba3fb1c20c318067807714b Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 7 Jan 2026 10:53:36 +0100 Subject: [PATCH 063/234] DPL: fix routing issues in forwarding If one (header, payload, ...) tuple in a MessageSet was to be copied, all the subsequent ones would have been copied. If one (header, payload, ...) tuple got redirected to more than one destination, all the subsequent ones would have been redirected there. --- Framework/Core/src/DataProcessingHelpers.cxx | 2 +- Framework/Core/test/test_ForwardInputs.cxx | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Framework/Core/src/DataProcessingHelpers.cxx b/Framework/Core/src/DataProcessingHelpers.cxx index 76730e9edab4e..90dcee52d73da 100644 --- a/Framework/Core/src/DataProcessingHelpers.cxx +++ b/Framework/Core/src/DataProcessingHelpers.cxx @@ -240,7 +240,6 @@ auto DataProcessingHelpers::routeForwardedMessages(FairMQDeviceProxy& proxy, for (size_t ii = 0, ie = currentSetOfInputs.size(); ii < ie; ++ii) { auto& messageSet = currentSetOfInputs[ii]; - forwardingChoices.clear(); for (size_t pi = 0; pi < messageSet.size(); ++pi) { auto& header = messageSet.header(pi); @@ -291,6 +290,7 @@ auto DataProcessingHelpers::routeForwardedMessages(FairMQDeviceProxy& proxy, // - If it's a message of the kind [header0][payload1][payload2][payload3]... and therefore // we will already use the same choice in the for loop below. if (dh->splitPayloadIndex == 0 || dh->splitPayloadParts <= 1 || messageSet.getNumberOfPayloads(pi) > 0) { + forwardingChoices.clear(); proxy.getMatchingForwardChannelIndexes(forwardingChoices, *dh, dph->startTime); } diff --git a/Framework/Core/test/test_ForwardInputs.cxx b/Framework/Core/test/test_ForwardInputs.cxx index 5add90ec8f18e..7ddbc831edad2 100644 --- a/Framework/Core/test/test_ForwardInputs.cxx +++ b/Framework/Core/test/test_ForwardInputs.cxx @@ -614,8 +614,7 @@ TEST_CASE("ForwardInputsSplitPayload") auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 2); // Two routes CHECK(result[0].Size() == 2); // No messages on this route - CHECK(result[1].Size() == 5); // FIXME: Multipart matching has side effects also for the elements - // CHECK(result[1].Size() == 3); // FIXME: the correct forwarding is that only the multipart goes to the same route + CHECK(result[1].Size() == 3); } TEST_CASE("ForwardInputEOSSingleRoute") From c426fe5cb1ad85f34394d53e6c15a19283cae76e Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Mon, 10 Nov 2025 10:30:15 +0100 Subject: [PATCH 064/234] ITS: remove CookedTracker Signed-off-by: Felix Schlepper --- .../ITSMFT/ITS/reconstruction/CMakeLists.txt | 7 +- .../ITSReconstruction/CookedConfigParam.h | 42 - .../include/ITSReconstruction/CookedTracker.h | 267 ------ .../reconstruction/src/CookedConfigParam.cxx | 22 - .../ITS/reconstruction/src/CookedTracker.cxx | 865 ------------------ .../reconstruction/src/CookedTrackerLinkDef.h | 26 - .../src/ITSReconstructionLinkDef.h | 4 - Detectors/ITSMFT/ITS/workflow/CMakeLists.txt | 1 - .../include/ITSWorkflow/CookedTrackerSpec.h | 75 -- .../include/ITSWorkflow/RecoWorkflow.h | 2 +- .../ITS/workflow/src/CookedTrackerSpec.cxx | 327 ------- .../ITSMFT/ITS/workflow/src/RecoWorkflow.cxx | 60 +- .../ITS/workflow/src/its-reco-workflow.cxx | 5 +- macro/CMakeLists.txt | 34 - macro/run_trac_its.C | 222 ----- 15 files changed, 30 insertions(+), 1929 deletions(-) delete mode 100644 Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedConfigParam.h delete mode 100644 Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedTracker.h delete mode 100644 Detectors/ITSMFT/ITS/reconstruction/src/CookedConfigParam.cxx delete mode 100644 Detectors/ITSMFT/ITS/reconstruction/src/CookedTracker.cxx delete mode 100644 Detectors/ITSMFT/ITS/reconstruction/src/CookedTrackerLinkDef.h delete mode 100644 Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/CookedTrackerSpec.h delete mode 100644 Detectors/ITSMFT/ITS/workflow/src/CookedTrackerSpec.cxx delete mode 100644 macro/run_trac_its.C diff --git a/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt b/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt index 3e1544c65b9de..a5004418599e4 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt @@ -11,8 +11,6 @@ o2_add_library(ITSReconstruction SOURCES src/ClustererTask.cxx - src/CookedTracker.cxx - src/CookedConfigParam.cxx src/RecoGeomHelper.cxx src/FastMultEstConfig.cxx src/FastMultEst.cxx @@ -24,9 +22,6 @@ o2_add_library(ITSReconstruction o2_target_root_dictionary( ITSReconstruction HEADERS include/ITSReconstruction/ClustererTask.h - include/ITSReconstruction/CookedTracker.h - include/ITSReconstruction/CookedConfigParam.h include/ITSReconstruction/RecoGeomHelper.h include/ITSReconstruction/FastMultEst.h - include/ITSReconstruction/FastMultEstConfig.h - LINKDEF src/CookedTrackerLinkDef.h) + include/ITSReconstruction/FastMultEstConfig.h) diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedConfigParam.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedConfigParam.h deleted file mode 100644 index bfc111d0a3803..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedConfigParam.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef ALICEO2_COOKEDTRACKINGPARAM_H_ -#define ALICEO2_COOKEDTRACKINGPARAM_H_ - -#include "CommonUtils/ConfigurableParamHelper.h" - -namespace o2 -{ -namespace its -{ - -struct CookedConfigParam : public o2::conf::ConfigurableParamHelper { - // seed "windows" in z and phi: makeSeeds - float zWin = 0.33; - float minPt = 0.05; - // Maximal accepted impact parameters for the seeds - float maxDCAxy = 3.; - float maxDCAz = 3.; - // Space-point resolution - float sigma = 0.0005; - // Tracking "road" from layer to layer - float roadY = 0.2; - float roadZ = 0.3; - // Minimal number of attached clusters - int minNumberOfClusters = 4; - - O2ParamDef(CookedConfigParam, "ITSCookedTracker"); -}; - -} // namespace its -} // namespace o2 -#endif diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedTracker.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedTracker.h deleted file mode 100644 index 918f7f82cbff8..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/CookedTracker.h +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file CookedTracker.h -/// \brief Definition of the "Cooked Matrix" ITS tracker -/// \author iouri.belikov@cern.ch - -#ifndef ALICEO2_ITS_COOKEDTRACKER_H -#define ALICEO2_ITS_COOKEDTRACKER_H - -//------------------------------------------------------------------------- -// A stand-alone ITS tracker -// The pattern recongintion based on the "cooked covariance" approach -//------------------------------------------------------------------------- - -#include -#include -#include "ITSBase/GeometryTGeo.h" -#include "MathUtils/Cartesian.h" -#include "DataFormatsITSMFT/Cluster.h" -#include "DataFormatsITS/TrackITS.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "ReconstructionDataFormats/Vertex.h" -#include "ITSReconstruction/CookedConfigParam.h" - -using Point3Df = o2::math_utils::Point3D; - -namespace o2 -{ -class MCCompLabel; -namespace dataformats -{ -template -class MCTruthContainer; -} -namespace itsmft -{ -class TopologyDictionary; -class CompClusterExt; -} // namespace itsmft -namespace its -{ -class CookedTracker -{ - using Cluster = o2::itsmft::Cluster; - using CompClusterExt = o2::itsmft::CompClusterExt; - using Vertex = o2::dataformats::Vertex>; - - public: - CookedTracker(Int_t nThreads = 1); - CookedTracker(const CookedTracker&) = delete; - CookedTracker& operator=(const CookedTracker& tr) = delete; - ~CookedTracker() = default; - - void setConfigParams() - { - const auto& par = CookedConfigParam::Instance(); - LOG(info) << " Setting configurable parameters..."; - - gzWin = par.zWin; - gminPt = par.minPt; - gmaxDCAxy = par.maxDCAxy; - gmaxDCAz = par.maxDCAz; - gSigma2 = par.sigma * par.sigma; - gRoadY = par.roadY; - gRoadZ = par.roadZ; - gminNumberOfClusters = par.minNumberOfClusters; - } - void setParameters(const std::vector& par) - { - gzWin = par[0]; - gminPt = par[1]; - gmaxDCAxy = par[3]; - gmaxDCAz = par[4]; - gSeedingLayer1 = par[5]; - gSeedingLayer2 = par[6]; - gSeedingLayer3 = par[7]; - gSigma2 = par[8] * par[8]; - gmaxChi2PerCluster = par[9]; - gmaxChi2PerTrack = par[10]; - gRoadY = par[11]; - gRoadZ = par[12]; - gminNumberOfClusters = par[13]; - } - void setParametersCosmics() - { - // seed "windows" in z and phi: makeSeeds - gzWin = 84.; // length of the L3 - gminPt = 10.; - // Maximal accepted impact parameters for the seeds - gmaxDCAxy = 19.4; // radius of the L3 - gmaxDCAz = 42.; // half-lenght of the L3 - // Space point resolution - gSigma2 = 0.2 * 0.2; - // Tracking "road" from layer to layer - gRoadY = 1.5; // Chip size in Y - gRoadZ = 3.0; // Chip size in Z - } - - void setVertices(const std::vector& vertices) - { - mVertices = &vertices; - } - - Double_t getX() const { return mX; } - Double_t getY() const { return mY; } - Double_t getZ() const { return mZ; } - Double_t getSigmaX() const { return mSigmaX; } - Double_t getSigmaY() const { return mSigmaY; } - Double_t getSigmaZ() const { return mSigmaZ; } - o2::MCCompLabel cookLabel(TrackITSExt& t, Float_t wrong) const; - void setExternalIndices(TrackITSExt& t) const; - Double_t getBz() const; - void setBz(Double_t bz) { mBz = bz; } - - void setNumberOfThreads(Int_t n) { mNumOfThreads = n; } - Int_t getNumberOfThreads() const { return mNumOfThreads; } - - using TrackInserter = std::function; - // These functions must be implemented - template - void process(gsl::span clusters, gsl::span::iterator& it, const o2::itsmft::TopologyDictionary* dict, U& tracks, V& clusIdx, o2::itsmft::ROFRecord& rof) - { - TrackInserter inserter = [&tracks, &clusIdx, this](const TrackITSExt& t) -> int { - // convert internal track to output format - auto& trackNew = tracks.emplace_back(t); - int noc = t.getNumberOfClusters(); - int clEntry = clusIdx.size(); - for (int i = 0; i < noc; i++) { - const Cluster* c = this->getCluster(t.getClusterIndex(i)); - Int_t idx = c - &mClusterCache[0]; // Index of this cluster in event - clusIdx.emplace_back(this->mFirstInFrame + idx); - } - trackNew.setClusterRefs(clEntry, noc); - trackNew.setPattern(0x7f); // this tracker finds only complete tracks - return tracks.size(); - }; - process(clusters, it, dict, inserter, rof); - } - void process(gsl::span const& clusters, gsl::span::iterator& it, const o2::itsmft::TopologyDictionary* dict, TrackInserter& inserter, o2::itsmft::ROFRecord& rof); - const Cluster* getCluster(Int_t index) const; - - void setGeometry(o2::its::GeometryTGeo* geom); - void setMCTruthContainers(const o2::dataformats::MCTruthContainer* clsLabels, std::vector* trkLabels) - { - mClsLabels = clsLabels; - mTrkLabels = trkLabels; - } - - void setContinuousMode(bool mode) { mContinuousMode = mode; } - bool getContinuousMode() { return mContinuousMode; } - - static void setMostProbablePt(float pt) { mMostProbablePt = pt; } - static auto getMostProbablePt() { return mMostProbablePt; } - - // internal helper classes - class ThreadData; - class Layer; - - protected: - static constexpr int kNLayers = 7; - int loadClusters(); - void unloadClusters(); - std::tuple processLoadedClusters(TrackInserter& inserter); - - std::vector trackInThread(Int_t first, Int_t last); - o2::its::TrackITSExt cookSeed(const Point3Df& r1, Point3Df& r2, const Point3Df& tr3, float rad2, float rad3, float_t alpha, float_t bz); - void makeSeeds(std::vector& seeds, Int_t first, Int_t last); - void trackSeeds(std::vector& seeds); - - Bool_t attachCluster(Int_t& volID, Int_t nl, Int_t ci, TrackITSExt& t, const TrackITSExt& o) const; - - void makeBackPropParam(std::vector& seeds) const; - bool makeBackPropParam(TrackITSExt& track) const; - - private: - /*** Tracking parameters ***/ - // seed "windows" in z and phi: makeSeeds - static Float_t gzWin; - static Float_t gminPt; - static Float_t mMostProbablePt; ///< settable most probable pt - // Maximal accepted impact parameters for the seeds - static Float_t gmaxDCAxy; - static Float_t gmaxDCAz; - // Layers for the seeding - static Int_t gSeedingLayer1; - static Int_t gSeedingLayer2; - static Int_t gSeedingLayer3; - // Space point resolution - static Float_t gSigma2; - // Max accepted chi2 - static Float_t gmaxChi2PerCluster; - static Float_t gmaxChi2PerTrack; - // Tracking "road" from layer to layer - static Float_t gRoadY; - static Float_t gRoadZ; - // Minimal number of attached clusters - static Int_t gminNumberOfClusters; - - bool mContinuousMode = true; ///< triggered or cont. mode - const o2::its::GeometryTGeo* mGeom = nullptr; /// interface to geometry - const o2::dataformats::MCTruthContainer* mClsLabels = nullptr; /// Cluster MC labels - std::vector* mTrkLabels = nullptr; /// Track MC labels - std::uint32_t mFirstInFrame = 0; ///< Index of the 1st cluster of a frame (within the loaded vector of clusters) - - Int_t mNumOfThreads; ///< Number of tracking threads - - Double_t mBz; ///< Effective Z-component of the magnetic field (kG) - - const std::vector* mVertices = nullptr; - Double_t mX = 0.; ///< X-coordinate of the primary vertex - Double_t mY = 0.; ///< Y-coordinate of the primary vertex - Double_t mZ = 0.; ///< Z-coordinate of the primary vertex - - Double_t mSigmaX = 2.; ///< error of the primary vertex position in X - Double_t mSigmaY = 2.; ///< error of the primary vertex position in Y - Double_t mSigmaZ = 2.; ///< error of the primary vertex position in Z - - static Layer sLayers[kNLayers]; ///< Layers filled with clusters - std::vector mSeeds; ///< Track seeds - - std::vector mClusterCache; - - ClassDefNV(CookedTracker, 1); -}; - -class CookedTracker::Layer -{ - public: - Layer(); - Layer(const Layer&) = delete; - Layer& operator=(const Layer& tr) = delete; - - void init(); - Bool_t insertCluster(const Cluster* c); - void setR(Double_t r) { mR = r; } - void unloadClusters(); - void selectClusters(std::vector& s, Float_t phi, Float_t dy, Float_t z, Float_t dz); - Int_t findClusterIndex(Float_t z) const; - Float_t getR() const { return mR; } - const Cluster* getCluster(Int_t i) const { return mClusters[i]; } - Float_t getAlphaRef(Int_t i) const { return mAlphaRef[i]; } - Float_t getClusterPhi(Int_t i) const { return mPhi[i]; } - Int_t getNumberOfClusters() const { return mClusters.size(); } - void setGeometry(o2::its::GeometryTGeo* geom) { mGeom = geom; } - - protected: - enum { kNSectors = 21 }; - - Float_t mR; ///< mean radius of this layer - const o2::its::GeometryTGeo* mGeom = nullptr; ///< interface to geometry - std::vector mClusters; ///< All clusters - std::vector mAlphaRef; ///< alpha of the reference plane - std::vector mPhi; ///< cluster phi - std::vector> mSectors[kNSectors]; ///< Cluster indices sector-by-sector -}; -} // namespace its -} // namespace o2 -#endif /* ALICEO2_ITS_COOKEDTRACKER_H */ diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/CookedConfigParam.cxx b/Detectors/ITSMFT/ITS/reconstruction/src/CookedConfigParam.cxx deleted file mode 100644 index 81087744b04a9..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/src/CookedConfigParam.cxx +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "ITSReconstruction/CookedConfigParam.h" - -namespace o2 -{ -namespace its -{ -static auto& sITSCookedTrackerParam = o2::its::CookedConfigParam::Instance(); - -O2ParamImpl(o2::its::CookedConfigParam); -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/CookedTracker.cxx b/Detectors/ITSMFT/ITS/reconstruction/src/CookedTracker.cxx deleted file mode 100644 index 5c804f6705dfd..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/src/CookedTracker.cxx +++ /dev/null @@ -1,865 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file CookedTracker.cxx -/// \brief Implementation of the "Cooked Matrix" ITS tracker -/// \author iouri.belikov@cern.ch - -//------------------------------------------------------------------------- -// A stand-alone ITS tracker -// The pattern recongintion based on the "cooked covariance" approach -//------------------------------------------------------------------------- -#include -#include -#include - -#include -#include - -#include - -#include "CommonConstants/MathConstants.h" -#include "DetectorsBase/Propagator.h" -#include "Field/MagneticField.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/TopologyDictionary.h" -#include "ITSReconstruction/CookedTracker.h" -#include "MathUtils/Utils.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" - -using namespace o2::its; -using namespace o2::itsmft; -using namespace o2::constants::math; -using o2::field::MagneticField; -using Label = o2::MCCompLabel; - -/*** Tracking parameters ***/ -// seed "windows" in z and phi: makeSeeds -Float_t CookedTracker::gzWin = 0.33; -Float_t CookedTracker::gminPt = 0.05; -Float_t CookedTracker::mMostProbablePt = o2::track::kMostProbablePt; -// Maximal accepted impact parameters for the seeds -Float_t CookedTracker::gmaxDCAxy = 3.; -Float_t CookedTracker::gmaxDCAz = 3.; -// Layers for the seeding -Int_t CookedTracker::gSeedingLayer1 = 6; -Int_t CookedTracker::gSeedingLayer2 = 4; -Int_t CookedTracker::gSeedingLayer3 = 5; -// Space point resolution -Float_t CookedTracker::gSigma2 = 0.0005 * 0.0005; -// Max accepted chi2 -Float_t CookedTracker::gmaxChi2PerCluster = 20.; -Float_t CookedTracker::gmaxChi2PerTrack = 30.; -// Tracking "road" from layer to layer -Float_t CookedTracker::gRoadY = 0.2; -Float_t CookedTracker::gRoadZ = 0.3; -// Minimal number of attached clusters -Int_t CookedTracker::gminNumberOfClusters = 4; - -const float kPI = 3.14159f; -const float k2PI = 2 * kPI; - -//************************************************ -// TODO: -//************************************************ -// Seeding: -// Precalculate cylidnrical (r,phi) for the clusters; -// use exact r's for the clusters - -CookedTracker::Layer CookedTracker::sLayers[CookedTracker::kNLayers]; - -CookedTracker::CookedTracker(Int_t n) : mNumOfThreads(n), mBz(0.) -{ - //-------------------------------------------------------------------- - // This default constructor needs to be provided - //-------------------------------------------------------------------- - const Double_t klRadius[7] = {2.34, 3.15, 3.93, 19.61, 24.55, 34.39, 39.34}; // tdr6 - - for (Int_t i = 0; i < kNLayers; i++) { - sLayers[i].setR(klRadius[i]); - } -} - -//__________________________________________________________________________ -Label CookedTracker::cookLabel(TrackITSExt& t, Float_t wrong) const -{ - //-------------------------------------------------------------------- - // This function "cooks" a track label. - // A label<0 indicates that some of the clusters are wrongly assigned. - //-------------------------------------------------------------------- - Int_t noc = t.getNumberOfClusters(); - std::map labelOccurence; - - for (int i = noc; i--;) { - const Cluster* c = getCluster(t.getClusterIndex(i)); - Int_t idx = c - &mClusterCache[0] + mFirstInFrame; // Index of this cluster in event - auto labels = mClsLabels->getLabels(idx); - - for (auto lab : labels) { // check all labels of the cluster - if (lab.isEmpty()) { - break; // all following labels will be empty also - } - // was this label already accounted for ? - labelOccurence[lab]++; - } - } - Label lab; - Int_t maxL = 0; // find most encountered label - for (auto [label, count] : labelOccurence) { - if (count <= maxL) { - continue; - } - maxL = count; - lab = label; - } - - if ((1. - Float_t(maxL) / noc) > wrong) { - // change the track ID to negative - lab.setFakeFlag(); - } - // t.SetFakeRatio((1.- Float_t(maxL)/noc)); - return lab; -} - -Double_t CookedTracker::getBz() const -{ - return mBz; -} - -static Double_t f1(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Double_t x3, Double_t y3) -{ - //----------------------------------------------------------------- - // Initial approximation of the track curvature - //----------------------------------------------------------------- - Double_t d = (x2 - x1) * (y3 - y2) - (x3 - x2) * (y2 - y1); - Double_t a = - 0.5 * ((y3 - y2) * (y2 * y2 - y1 * y1 + x2 * x2 - x1 * x1) - (y2 - y1) * (y3 * y3 - y2 * y2 + x3 * x3 - x2 * x2)); - Double_t b = - 0.5 * ((x2 - x1) * (y3 * y3 - y2 * y2 + x3 * x3 - x2 * x2) - (x3 - x2) * (y2 * y2 - y1 * y1 + x2 * x2 - x1 * x1)); - - Double_t xr = TMath::Abs(d / (d * x1 - a)), yr = TMath::Abs(d / (d * y1 - b)); - - Double_t crv = xr * yr / sqrt(xr * xr + yr * yr); - if (d > 0) { - crv = -crv; - } - - return crv; -} - -static Double_t f2(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Double_t x3, Double_t y3) -{ - //----------------------------------------------------------------- - // Initial approximation of the x-coordinate of the center of curvature - //----------------------------------------------------------------- - - Double_t k1 = (y2 - y1) / (x2 - x1), k2 = (y3 - y2) / (x3 - x2); - Double_t x0 = 0.5 * (k1 * k2 * (y1 - y3) + k2 * (x1 + x2) - k1 * (x2 + x3)) / (k2 - k1); - - return x0; -} - -static Double_t f3(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Double_t z1, Double_t z2) -{ - //----------------------------------------------------------------- - // Initial approximation of the tangent of the track dip angle - //----------------------------------------------------------------- - return (z1 - z2) / sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); -} - -o2::its::TrackITSExt CookedTracker::cookSeed(const Point3Df& r1, Point3Df& r2, const Point3Df& tr3, float rad2, float rad3, float_t alpha, float_t bz) -// const Float_t r1[4], const Float_t r2[4], const Float_t tr3[4], Double_t alpha, Double_t bz) -{ - //-------------------------------------------------------------------- - // This is the main cooking function. - // Creates seed parameters out of provided clusters. - //-------------------------------------------------------------------- - - Double_t ca = TMath::Cos(alpha), sa = TMath::Sin(alpha); - Double_t x1 = r1.X() * ca + r1.Y() * sa, y1 = -r1.X() * sa + r1.Y() * ca, z1 = r1.Z(); - Double_t x2 = r2.X() * ca + r2.Y() * sa, y2 = -r2.X() * sa + r2.Y() * ca, z2 = r2.Z(); - Double_t x3 = tr3.X(), y3 = tr3.Y(), z3 = tr3.Z(); - - std::array par; - par[0] = y3; - par[1] = z3; - Double_t crv = f1(x1, y1, x2, y2, x3, y3); // curvature - Double_t x0 = f2(x1, y1, x2, y2, x3, y3); // x-coordinate of the center - Double_t tgl12 = f3(x1, y1, x2, y2, z1, z2); - Double_t tgl23 = f3(x2, y2, x3, y3, z2, z3); - - Double_t sf = crv * (x3 - x0); // FIXME: sf must never be >= kAlmost1 - par[2] = sf; - - par[3] = 0.5 * (tgl12 + tgl23); - par[4] = (TMath::Abs(bz) < Almost0) ? 1 / CookedTracker::getMostProbablePt() : crv / (bz * B2C); - - std::array cov; - /* - for (Int_t i=0; i<15; i++) cov[i]=0.; - cov[0] =gSigma2*10; - cov[2] =gSigma2*10; - cov[5] =0.007*0.007*10; //FIXME all these lines - cov[9] =0.007*0.007*10; - cov[14]=0.1*0.1*10; - */ - const Double_t dlt = 0.0005; - Double_t fy = 1. / (rad2 - rad3); - Double_t tz = fy; - const auto big = sqrt(o2::constants::math::VeryBig); - auto cy = big; - if (TMath::Abs(bz) >= Almost0) { - auto tmp = dlt * bz * B2C; - cy = (f1(x1, y1, x2, y2 + dlt, x3, y3) - crv) / tmp; - cy *= 20; // FIXME: MS contribution to the cov[14] - } - Double_t s2 = gSigma2; - - cov[0] = s2; - cov[1] = 0.; - cov[2] = s2; - cov[3] = s2 * fy; - cov[4] = 0.; - cov[5] = s2 * fy * fy; - cov[6] = 0.; - cov[7] = s2 * tz; - cov[8] = 0.; - cov[9] = s2 * tz * tz; - cov[10] = s2 * cy; - cov[11] = 0.; - cov[12] = s2 * fy * cy; - cov[13] = 0.; - cov[14] = s2 * cy * cy; - - return o2::its::TrackITSExt(x3, alpha, par, cov); -} - -void CookedTracker::makeSeeds(std::vector& seeds, Int_t first, Int_t last) -{ - //-------------------------------------------------------------------- - // This is the main pattern recongition function. - // Creates seeds out of two clusters and another point. - //-------------------------------------------------------------------- - const float zv = getZ(); - - Layer& layer1 = sLayers[gSeedingLayer1]; - Layer& layer2 = sLayers[gSeedingLayer2]; - Layer& layer3 = sLayers[gSeedingLayer3]; - - auto bz = getBz(); - const Double_t maxC = (TMath::Abs(bz) < Almost0) ? 0.03 : TMath::Abs(bz * B2C / gminPt); - const Double_t kpWinC = TMath::ASin(0.5 * maxC * layer1.getR()) - TMath::ASin(0.5 * maxC * layer2.getR()); - const Double_t kpWinD = 2 * (TMath::ASin(gmaxDCAxy / layer2.getR()) - TMath::ASin(gmaxDCAxy / layer1.getR())); - const Double_t kpWin = std::max(kpWinC, kpWinD); - - for (Int_t n1 = first; n1 < last; n1++) { - const Cluster* c1 = layer1.getCluster(n1); - // - //auto lab = (mClsLabels->getLabels(c1 - &mClusterCache[0] + mFirstInFrame))[0]; - // - auto xyz1 = c1->getXYZGloRot(*mGeom); - auto z1 = xyz1.Z(); - auto r1 = xyz1.rho(); - - auto phi1 = layer1.getClusterPhi(n1); - auto tgl = std::abs((z1 - zv) / r1); - - auto zr2 = zv + layer2.getR() / r1 * (z1 - zv); - auto phir2 = phi1; - auto dz2 = gzWin * (1 + 2 * tgl); - - std::vector selected2; - float dy2 = kpWin * layer2.getR(); - layer2.selectClusters(selected2, phir2, dy2, zr2, dz2); - for (auto n2 : selected2) { - const Cluster* c2 = layer2.getCluster(n2); - // - //if ((mClsLabels->getLabels(c2 - &mClusterCache[0] + mFirstInFrame))[0] != lab) continue; - // - auto xyz2 = c2->getXYZGloRot(*mGeom); - auto z2 = xyz2.Z(); - auto r2 = xyz2.rho(); - - auto dx = xyz2.X() - xyz1.X(), dy = xyz2.Y() - xyz1.Y(); - auto d = (dx * xyz1.Y() - dy * xyz1.X()) / TMath::Sqrt(dx * dx + dy * dy); - auto phir3 = phi1 + TMath::ASin(d / r1) - TMath::ASin(d / layer3.getR()); - - auto zr3 = z1 + (layer3.getR() - r1) / (r2 - r1) * (z2 - z1); - auto dz3 = 0.5f * dz2; - - std::vector selected3; - float dy3 = 0.1 * kpWin * layer3.getR(); //Fixme - layer3.selectClusters(selected3, phir3, dy3, zr3, dz3); - for (auto n3 : selected3) { - const Cluster* c3 = layer3.getCluster(n3); - // - //if ((mClsLabels->getLabels(c3 - &mClusterCache[0] + mFirstInFrame))[0] != lab) continue; - // - auto xyz3 = c3->getXYZGloRot(*mGeom); - auto z3 = xyz3.Z(); - auto r3 = xyz3.rho(); - - zr3 = z1 + (r3 - r1) / (r2 - r1) * (z2 - z1); - if (std::abs(z3 - zr3) > 0.2 * dz3) { - continue; - } - - const Point3Df& txyz2 = c2->getXYZ(); // tracking coordinates - - TrackITSExt seed = cookSeed(xyz1, xyz3, txyz2, layer2.getR(), layer3.getR(), layer2.getAlphaRef(n2), getBz()); - - float ip[2]; - seed.getImpactParams(getX(), getY(), getZ(), getBz(), ip); - if (TMath::Abs(ip[0]) > gmaxDCAxy) { - continue; - } - if (TMath::Abs(ip[1]) > gmaxDCAz) { - continue; - } - { - Double_t xx0 = 0.008; // Rough layer thickness - Double_t radl = 9.36; // Radiation length of Si [cm] - Double_t rho = 2.33; // Density of Si [g/cm^3] - if (!seed.correctForMaterial(xx0, xx0 * radl * rho, kTRUE)) { - continue; - } - } - seed.setClusterIndex(gSeedingLayer1, n1); - seed.setClusterIndex(gSeedingLayer3, n3); - seed.setClusterIndex(gSeedingLayer2, n2); - seeds.push_back(seed); - } - } - } - /* - for (Int_t n1 = 0; n1 < nClusters1; n1++) { - Cluster* c1 = layer1.getCluster(n1); - ((Cluster*)c1)->goToFrameTrk(); - } - for (Int_t n2 = 0; n2 < nClusters2; n2++) { - Cluster* c2 = layer2.getCluster(n2); - ((Cluster*)c2)->goToFrameTrk(); - } - for (Int_t n3 = 0; n3 < nClusters3; n3++) { - Cluster* c3 = layer3.getCluster(n3); - ((Cluster*)c3)->goToFrameTrk(); - } - */ -} - -void CookedTracker::trackSeeds(std::vector& seeds) -{ - //-------------------------------------------------------------------- - // Loop over a subset of track seeds - //-------------------------------------------------------------------- - std::vector used[gSeedingLayer2]; - std::vector selec[gSeedingLayer2]; - for (Int_t l = gSeedingLayer2 - 1; l >= 0; l--) { - Int_t n = sLayers[l].getNumberOfClusters(); - used[l].resize(n, false); - selec[l].reserve(n / 100); - } - - for (auto& track : seeds) { - auto x = track.getX(); - auto y = track.getY(); - Float_t phi = track.getAlpha() + TMath::ATan2(y, x); - o2::math_utils::bringTo02Pi(phi); - float ip[2]; - track.getImpactParams(getX(), getY(), getZ(), getBz(), ip); - - auto z = track.getZ(); - auto crv = track.getCurvature(getBz()); - auto tgl = track.getTgl(); - Float_t r1 = sLayers[gSeedingLayer2].getR(); - - for (Int_t l = gSeedingLayer2 - 1; l >= 0; l--) { - Float_t r2 = sLayers[l].getR(); - selec[l].clear(); - if (TMath::Abs(ip[0]) > r2) { - break; - } - if (TMath::Abs(crv) < gRoadY / (0.5 * r1 * 0.5 * r1)) { - phi += TMath::ASin(ip[0] / r2) - TMath::ASin(ip[0] / r1); - z += tgl * (TMath::Sqrt(r2 * r2 - ip[0] * ip[0]) - TMath::Sqrt(r1 * r1 - ip[0] * ip[0])); - } else { // Fixme - phi += 0.5 * crv * (r2 - r1); - z += tgl / (0.5 * crv) * (TMath::ASin(0.5 * crv * r2) - TMath::ASin(0.5 * crv * r1)); - } - sLayers[l].selectClusters(selec[l], phi, gRoadY, z, gRoadZ * (1 + 2 * std::abs(tgl))); - r1 = r2; - } - - TrackITSExt best(track); - - Int_t volID = -1; - for (auto& ci3 : selec[3]) { - TrackITSExt t3(track); - if (used[3][ci3]) { - continue; - } - if (!attachCluster(volID, 3, ci3, t3, track)) { - continue; - } - if (t3.isBetter(best, gmaxChi2PerTrack)) { - best = t3; - } - - for (auto& ci2 : selec[2]) { - TrackITSExt t2(t3); - if (used[2][ci2]) { - continue; - } - if (!attachCluster(volID, 2, ci2, t2, t3)) { - continue; - } - if (t2.isBetter(best, gmaxChi2PerTrack)) { - best = t2; - } - - for (auto& ci1 : selec[1]) { - TrackITSExt t1(t2); - if (used[1][ci1]) { - continue; - } - if (!attachCluster(volID, 1, ci1, t1, t2)) { - continue; - } - if (t1.isBetter(best, gmaxChi2PerTrack)) { - best = t1; - } - - for (auto& ci0 : selec[0]) { - TrackITSExt t0(t1); - if (used[0][ci0]) { - continue; - } - if (!attachCluster(volID, 0, ci0, t0, t1)) { - continue; - } - if (t0.isBetter(best, gmaxChi2PerTrack)) { - best = t0; - } - volID = -1; - } - } - } - } - - if (best.getNumberOfClusters() >= gminNumberOfClusters) { - Int_t noc = best.getNumberOfClusters(); - for (Int_t ic = 3; ic < noc; ic++) { - Int_t index = best.getClusterIndex(ic); - Int_t l = (index & 0xf0000000) >> 28, c = (index & 0x0fffffff); - used[l][c] = true; - } - } - track = best; - } -} - -std::vector CookedTracker::trackInThread(Int_t first, Int_t last) -{ - //-------------------------------------------------------------------- - // This function is passed to a tracking thread - //-------------------------------------------------------------------- - std::vector seeds; - seeds.reserve(last - first + 1); - - for (const auto& vtx : *mVertices) { - mX = vtx.getX(); - mY = vtx.getY(); - mZ = vtx.getZ(); - makeSeeds(seeds, first, last); - } - - std::sort(seeds.begin(), seeds.end()); - - trackSeeds(seeds); - - makeBackPropParam(seeds); - - return seeds; -} - -void CookedTracker::process(gsl::span const& clusters, - gsl::span::iterator& pattIt, - const o2::itsmft::TopologyDictionary* dict, - TrackInserter& inserter, - o2::itsmft::ROFRecord& rof) -{ - //-------------------------------------------------------------------- - // This is the main tracking function - //-------------------------------------------------------------------- - if (mVertices == nullptr || mVertices->empty()) { - LOG(info) << "Not a single primary vertex provided. Skipping...\n"; - return; - } - LOG(info) << "\n CookedTracker::process(), number of threads: " << mNumOfThreads; - - auto start = std::chrono::system_clock::now(); - - mFirstInFrame = rof.getFirstEntry(); - - mClusterCache.reserve(rof.getNEntries()); - auto clusters_in_frame = rof.getROFData(clusters); - for (const auto& comp : clusters_in_frame) { - - auto pattID = comp.getPatternID(); - o2::math_utils::Point3D locXYZ; - float sigmaY2 = gSigma2, sigmaZ2 = gSigma2; - if (pattID != itsmft::CompCluster::InvalidPatternID) { - sigmaY2 = gSigma2; //dict.getErr2X(pattID); - sigmaZ2 = gSigma2; //dict.getErr2Z(pattID); - if (!dict->isGroup(pattID)) { - locXYZ = dict->getClusterCoordinates(comp); - } else { - o2::itsmft::ClusterPattern patt(pattIt); - locXYZ = dict->getClusterCoordinates(comp, patt); - } - } else { - o2::itsmft::ClusterPattern patt(pattIt); - locXYZ = dict->getClusterCoordinates(comp, patt, false); - } - auto sensorID = comp.getSensorID(); - // Inverse transformation to the local --> tracking - auto trkXYZ = mGeom->getMatrixT2L(sensorID) ^ locXYZ; - - Cluster c; - c.setSensorID(sensorID); - c.setPos(trkXYZ); - c.setErrors(sigmaY2, sigmaZ2, 0.f); - mClusterCache.push_back(c); - } - - auto nClFrame = loadClusters(); - - auto end = std::chrono::system_clock::now(); - std::chrono::duration diff = end - start; - LOG(info) << "Loading clusters: " << nClFrame << " in a single frame : " << diff.count() << " s"; - - start = end; - - auto [first, number] = processLoadedClusters(inserter); - rof.setFirstEntry(first); - rof.setNEntries(number); - - unloadClusters(); - end = std::chrono::system_clock::now(); - diff = end - start; - LOG(info) << "Processing time/clusters for single frame : " << diff.count() << " / " << nClFrame << " s"; - - start = end; -} - -std::tuple CookedTracker::processLoadedClusters(TrackInserter& inserter) -{ - //-------------------------------------------------------------------- - // This is the main tracking function for single frame, it is assumed that only clusters - // which may contribute to this frame is loaded - //-------------------------------------------------------------------- - Int_t numOfClusters = sLayers[gSeedingLayer1].getNumberOfClusters(); - if (!numOfClusters) { - return {0, 0}; - } - - std::vector>> futures(mNumOfThreads); - std::vector> seedArray(mNumOfThreads); - - for (Int_t t = 0, first = 0; t < mNumOfThreads; t++) { - Int_t rem = t < (numOfClusters % mNumOfThreads) ? 1 : 0; - Int_t last = first + (numOfClusters / mNumOfThreads) + rem; - futures[t] = std::async(std::launch::async, &CookedTracker::trackInThread, this, first, last); - first = last; - } - Int_t nSeeds = 0, ngood = 0; - int nAllTracks = 0, nTracks = 0; - for (Int_t t = 0; t < mNumOfThreads; t++) { - seedArray[t] = futures[t].get(); - nSeeds += seedArray[t].size(); - for (auto& track : seedArray[t]) { - if (track.getNumberOfClusters() < gminNumberOfClusters) { - continue; - } - - o2::dataformats::VertexBase vtx; - track.propagateToDCA(vtx, getBz()); - - nAllTracks = inserter(track); - nTracks++; - if (mTrkLabels) { - Label label = cookLabel(track, 0.); // For comparison only - if (label.getTrackID() >= 0) { - ngood++; - } - // the inserter returns the size of the track vector, the index of the last - // inserted track is thus n - 1 - mTrkLabels->emplace_back(label); - } - } - } - - if (nSeeds) { - LOG(info) << "Found tracks: " << nTracks; - LOG(info) << "CookedTracker::processLoadedClusters(), good_tracks:/seeds: " << ngood << '/' << nSeeds << "-> " - << Float_t(ngood) / nSeeds << '\n'; - } - // returning index of the first track and the number of add tracks - // inserted in this call - return {nAllTracks - nTracks, nTracks}; -} - -//____________________________________________________________ -void CookedTracker::makeBackPropParam(std::vector& seeds) const -{ - // refit in backward direction - for (auto& track : seeds) { - if (track.getNumberOfClusters() < gminNumberOfClusters) { - continue; - } - makeBackPropParam(track); - } -} - -//____________________________________________________________ -bool CookedTracker::makeBackPropParam(TrackITSExt& track) const -{ - // refit in backward direction - auto backProp = track.getParamOut(); - backProp = track; - backProp.resetCovariance(); - auto propagator = o2::base::Propagator::Instance(); - - Int_t noc = track.getNumberOfClusters(); - for (int ic = noc; ic--;) { // cluster indices are stored in inward direction - Int_t index = track.getClusterIndex(ic); - const Cluster* c = getCluster(index); - float alpha = mGeom->getSensorRefAlpha(c->getSensorID()); - if (!backProp.rotate(alpha)) { - return false; - } - if (!propagator->PropagateToXBxByBz(backProp, c->getX())) { - return false; - } - if (!backProp.update(static_cast&>(*c))) { - return false; - } - } - track.getParamOut() = backProp; - return true; -} - -int CookedTracker::loadClusters() -{ - //-------------------------------------------------------------------- - // This function reads the ITSU clusters from the tree, - // sort them, distribute over the internal tracker arrays, etc - //-------------------------------------------------------------------- - - if (mClusterCache.empty()) { - return 0; - } - - for (const auto& c : mClusterCache) { - Int_t layer = mGeom->getLayer(c.getSensorID()); - sLayers[layer].insertCluster(&c); - } - - std::vector> fut; - for (Int_t l = 0; l < kNLayers; l += mNumOfThreads) { - for (Int_t t = 0; t < mNumOfThreads; t++) { - if (l + t >= kNLayers) { - break; - } - auto f = std::async(std::launch::async, &CookedTracker::Layer::init, sLayers + (l + t)); - fut.push_back(std::move(f)); - } - for (size_t t = 0; t < fut.size(); t++) { - fut[t].wait(); - } - } - - return mClusterCache.size(); -} - -void CookedTracker::unloadClusters() -{ - //-------------------------------------------------------------------- - // This function unloads ITSU clusters from the RAM - //-------------------------------------------------------------------- - mClusterCache.clear(); - for (Int_t i = 0; i < kNLayers; i++) { - sLayers[i].unloadClusters(); - } -} - -const Cluster* CookedTracker::getCluster(Int_t index) const -{ - //-------------------------------------------------------------------- - // Return pointer to a given cluster - //-------------------------------------------------------------------- - Int_t l = (index & 0xf0000000) >> 28; - Int_t c = (index & 0x0fffffff) >> 00; - return sLayers[l].getCluster(c); -} - -CookedTracker::Layer::Layer() : mR(0) -{ - //-------------------------------------------------------------------- - // This default constructor needs to be provided - //-------------------------------------------------------------------- -} - -void CookedTracker::Layer::init() -{ - //-------------------------------------------------------------------- - // Sort clusters and cache their reference plane info in a thread - //-------------------------------------------------------------------- - std::sort(std::begin(mClusters), std::end(mClusters), - [](const Cluster* c1, const Cluster* c2) { return (c1->getZ() < c2->getZ()); }); - - Double_t r = 0.; - Int_t m = mClusters.size(); - for (Int_t i = 0; i < m; i++) { - const Cluster* c = mClusters[i]; - // Float_t xRef, aRef; - // mGeom->getSensorXAlphaRefPlane(c->getSensorID(),xRef, aRef); - mAlphaRef.push_back(mGeom->getSensorRefAlpha(c->getSensorID())); - auto xyz = c->getXYZGloRot(*mGeom); - r += xyz.rho(); - Float_t phi = xyz.Phi(); - o2::math_utils::bringTo02Pi(phi); - mPhi.push_back(phi); - Int_t s = phi * (int)kNSectors / k2PI; - mSectors[s < kNSectors ? s : kNSectors - 1].emplace_back(i, c->getZ()); - } - - if (m) { - mR = r / m; - } -} - -void CookedTracker::Layer::unloadClusters() -{ - //-------------------------------------------------------------------- - // Unload clusters from this layer - //-------------------------------------------------------------------- - mClusters.clear(); - mAlphaRef.clear(); - mPhi.clear(); - for (Int_t s = 0; s < kNSectors; s++) { - mSectors[s].clear(); - } -} - -Bool_t CookedTracker::Layer::insertCluster(const Cluster* c) -{ - //-------------------------------------------------------------------- - // This function inserts a cluster to this layer - //-------------------------------------------------------------------- - mClusters.push_back(c); - return kTRUE; -} - -Int_t CookedTracker::Layer::findClusterIndex(Float_t z) const -{ - //-------------------------------------------------------------------- - // This function returns the index of the first cluster with its fZ >= "z". - //-------------------------------------------------------------------- - auto found = std::upper_bound(std::begin(mClusters), std::end(mClusters), z, - [](Float_t zc, const Cluster* c) { return (zc < c->getZ()); }); - return found - std::begin(mClusters); -} - -void CookedTracker::Layer::selectClusters(std::vector& selec, Float_t phi, Float_t dy, Float_t z, Float_t dz) -{ - //-------------------------------------------------------------------- - // This function selects clusters within the "road" - //-------------------------------------------------------------------- - Float_t zMin = z - dz; - Float_t zMax = z + dz; - - o2::math_utils::bringTo02Pi(phi); - - Float_t dphi = dy / mR; - - int smin = (phi - dphi) / k2PI * (int)kNSectors; - int ds = (phi + dphi) / k2PI * (int)kNSectors - smin + 1; - - smin = (smin + kNSectors) % kNSectors; - - for (int is = 0; is < ds; is++) { - Int_t s = (smin + is) % kNSectors; - - auto cmp = [](Float_t zc, std::pair p) { return (zc < p.second); }; - auto imin = std::upper_bound(std::begin(mSectors[s]), std::end(mSectors[s]), zMin, cmp); - auto imax = std::upper_bound(imin, std::end(mSectors[s]), zMax, cmp); - for (; imin != imax; imin++) { - auto [i, zz] = *imin; - auto cdphi = std::abs(mPhi[i] - phi); - if (cdphi > dphi) { - if (cdphi > kPI) { - cdphi = k2PI - cdphi; - } - if (cdphi > dphi) { - continue; // check in Phi - } - } - selec.push_back(i); - } - } -} - -Bool_t CookedTracker::attachCluster(Int_t& volID, Int_t nl, Int_t ci, TrackITSExt& t, const TrackITSExt& o) const -{ - //-------------------------------------------------------------------- - // Try to attach a clusters with index ci to running track hypothesis - //-------------------------------------------------------------------- - Layer& layer = sLayers[nl]; - const Cluster* c = layer.getCluster(ci); - - Int_t vid = c->getSensorID(); - - if (vid != volID) { - volID = vid; - t = o; - Double_t alpha = layer.getAlphaRef(ci); - if (!t.propagate(alpha, c->getX(), getBz())) { - return kFALSE; - } - } - - Double_t chi2 = t.getPredictedChi2(*c); - if (chi2 > gmaxChi2PerCluster) { - return kFALSE; - } - - if (!t.update(*c, chi2)) { - return kFALSE; - } - t.setClusterIndex(nl, ci); - - Double_t xx0 = (nl > 2) ? 0.008 : 0.003; // Rough layer thickness - Double_t x0 = 9.36; // Radiation length of Si [cm] - Double_t rho = 2.33; // Density of Si [g/cm^3] - t.correctForMaterial(xx0, xx0 * x0 * rho, kTRUE); - return kTRUE; -} - -void CookedTracker::setGeometry(o2::its::GeometryTGeo* geom) -{ - /// attach geometry interface - mGeom = geom; - for (Int_t i = 0; i < kNLayers; i++) { - sLayers[i].setGeometry(geom); - } -} diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/CookedTrackerLinkDef.h b/Detectors/ITSMFT/ITS/reconstruction/src/CookedTrackerLinkDef.h deleted file mode 100644 index 1e8596fbb224c..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/src/CookedTrackerLinkDef.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifdef __CLING__ - -#pragma link off all globals; -#pragma link off all classes; -#pragma link off all functions; - -#pragma link C++ class o2::its::ClustererTask + ; -#pragma link C++ class o2::its::CookedTracker + ; -#pragma link C++ class o2::its::CookedConfigParam + ; -#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::its::CookedConfigParam> + ; -#pragma link C++ class o2::its::RecoGeomHelper + ; -#pragma link C++ class o2::its::FastMultEst + ; -#pragma link C++ class o2::its::FastMultEstConfig + ; - -#endif diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/ITSReconstructionLinkDef.h b/Detectors/ITSMFT/ITS/reconstruction/src/ITSReconstructionLinkDef.h index c93cf03d0ed3d..67622303fc840 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/src/ITSReconstructionLinkDef.h +++ b/Detectors/ITSMFT/ITS/reconstruction/src/ITSReconstructionLinkDef.h @@ -15,11 +15,7 @@ #pragma link off all classes; #pragma link off all functions; -#pragma link C++ class o2::its::ClustererTask + ; -#pragma link C++ class o2::its::CookedTracker + ; - #pragma link C++ class o2::its::RecoGeomHelper + ; - #pragma link C++ class o2::its::FastMultEst + ; #pragma link C++ class o2::its::FastMultEstConfig + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::its::FastMultEstConfig> + ; diff --git a/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt b/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt index 3609560eccf72..f0d50e59493d4 100644 --- a/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt @@ -16,7 +16,6 @@ o2_add_library(ITSWorkflow src/ClustererSpec.cxx src/ClusterWriterSpec.cxx src/TrackerSpec.cxx - src/CookedTrackerSpec.cxx src/TrackWriterSpec.cxx src/TrackReaderSpec.cxx src/VertexReaderSpec.cxx diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/CookedTrackerSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/CookedTrackerSpec.h deleted file mode 100644 index 4ecc98eed9cfb..0000000000000 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/CookedTrackerSpec.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file CookedTrackerSpec.h - -#ifndef O2_ITS_COOKEDTRACKERDPL -#define O2_ITS_COOKEDTRACKERDPL - -#include "Framework/DataProcessorSpec.h" -#include "ITSReconstruction/CookedTracker.h" -#include "ITStracking/TimeFrame.h" -#include "ITStracking/Vertexer.h" -#include "ITStracking/VertexerTraits.h" -#include "ITStracking/BoundedAllocator.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DataFormatsITSMFT/TopologyDictionary.h" -#include "Framework/Task.h" -#include "TStopwatch.h" -#include "DetectorsBase/GRPGeomHelper.h" - -#include - -using namespace o2::framework; - -namespace o2 -{ -namespace its -{ - -class CookedTrackerDPL : public Task -{ - public: - CookedTrackerDPL(std::shared_ptr gr, bool useMC, int trgType, TrackingMode::Type trMode); - ~CookedTrackerDPL() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - void endOfStream(framework::EndOfStreamContext& ec) final; - void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final; - void setClusterDictionary(const o2::itsmft::TopologyDictionary* d) { mDict = d; } - - private: - void updateTimeDependentParams(ProcessingContext& pc); - - std::shared_ptr mGGCCDBRequest; - int mState = 0; - bool mUseMC = true; - bool mRunVertexer = true; - int mUseTriggers = 0; - TrackingMode::Type mMode = TrackingMode::Sync; - const o2::itsmft::TopologyDictionary* mDict = nullptr; - std::unique_ptr mGRP = nullptr; - o2::its::CookedTracker mTracker; - std::unique_ptr> mVertexerTraitsPtr = nullptr; - std::unique_ptr> mVertexerPtr = nullptr; - std::shared_ptr mMemoryPool; - std::shared_ptr mTaskArena; - TStopwatch mTimer; -}; - -/// create a processor spec -/// run ITS CookedMatrix tracker -framework::DataProcessorSpec getCookedTrackerSpec(bool useMC, bool useGeom, int useTrig, TrackingMode::Type trMode); - -} // namespace its -} // namespace o2 - -#endif /* O2_ITS_COOKEDTRACKERDPL */ diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h index 90b38acb34a95..1d5d829a6f79a 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h @@ -26,7 +26,7 @@ namespace its namespace reco_workflow { -framework::WorkflowSpec getWorkflow(bool useMC, bool useCMtracker, TrackingMode::Type trmode, const bool overrideBeamPosition = false, +framework::WorkflowSpec getWorkflow(bool useMC, TrackingMode::Type trmode, const bool overrideBeamPosition = false, bool upstreamDigits = false, bool upstreamClusters = false, bool disableRootOutput = false, bool useGeom = false, int useTrig = 0, bool useGPUWF = false, o2::gpu::gpudatatypes::DeviceType dType = o2::gpu::gpudatatypes::DeviceType::CPU); } diff --git a/Detectors/ITSMFT/ITS/workflow/src/CookedTrackerSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/CookedTrackerSpec.cxx deleted file mode 100644 index b989a78e59b7c..0000000000000 --- a/Detectors/ITSMFT/ITS/workflow/src/CookedTrackerSpec.cxx +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file CookedTrackerSpec.cxx - -#include - -#include "TGeoGlobalMagField.h" - -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/CCDBParamSpec.h" -#include "ITSWorkflow/CookedTrackerSpec.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/Cluster.h" -#include "DataFormatsITS/TrackITS.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include -#include "ITSMFTBase/DPLAlpideParam.h" -#include "DataFormatsTRD/TriggerRecord.h" - -#include "Field/MagneticField.h" -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsBase/Propagator.h" -#include "ITSBase/GeometryTGeo.h" -#include "CommonDataFormat/IRFrame.h" -#include "ITStracking/IOUtils.h" -#include "DetectorsCommonDataFormats/DetectorNameConf.h" -#include "CommonUtils/StringUtils.h" - -#include "ITSReconstruction/FastMultEstConfig.h" -#include "ITSReconstruction/FastMultEst.h" -#include "ITSMFTReconstruction/ClustererParam.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace its -{ - -using Vertex = o2::dataformats::Vertex>; - -CookedTrackerDPL::CookedTrackerDPL(std::shared_ptr gr, bool useMC, int trgType, TrackingMode::Type trMode) : mGGCCDBRequest(gr), mUseMC(useMC), mUseTriggers{trgType}, mMode(trMode) -{ - mVertexerTraitsPtr = std::make_unique>(); - mVertexerPtr = std::make_unique>(mVertexerTraitsPtr.get()); -} - -void CookedTrackerDPL::init(InitContext& ic) -{ - mTimer.Stop(); - mTimer.Reset(); - o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); - auto nthreads = ic.options().get("nthreads"); - mTracker.setNumberOfThreads(nthreads); - mTaskArena = std::make_shared(nthreads); - mMemoryPool = std::make_unique(); - mVertexerPtr->setMemoryPool(mMemoryPool); - mVertexerPtr->setNThreads(nthreads, mTaskArena); - mVertexerTraitsPtr->setMemoryPool(mMemoryPool); -} - -void CookedTrackerDPL::run(ProcessingContext& pc) -{ - mTimer.Start(false); - updateTimeDependentParams(pc); - auto compClusters = pc.inputs().get>("compClusters"); - gsl::span patterns = pc.inputs().get>("patterns"); - - // code further down does assignment to the rofs and the altered object is used for output - // we therefore need a copy of the vector rather than an object created directly on the input data, - // the output vector however is created directly inside the message memory thus avoiding copy by - // snapshot - auto rofsinput = pc.inputs().get>("ROframes"); - gsl::span physTriggers; - std::vector fromTRD; - if (mUseTriggers == 2) { // use TRD triggers - o2::InteractionRecord ir{0, pc.services().get().firstTForbit}; - auto trdTriggers = pc.inputs().get>("phystrig"); - for (const auto& trig : trdTriggers) { - if (trig.getBCData() >= ir && trig.getNumberOfTracklets()) { - ir = trig.getBCData(); - fromTRD.emplace_back(o2::itsmft::PhysTrigger{ir, 0}); - } - } - physTriggers = gsl::span(fromTRD.data(), fromTRD.size()); - } else if (mUseTriggers == 1) { // use Phys triggers from ITS stream - physTriggers = pc.inputs().get>("phystrig"); - } - - auto& rofs = pc.outputs().make>(Output{"ITS", "ITSTrackROF", 0}, rofsinput.begin(), rofsinput.end()); - - std::unique_ptr> labels; - gsl::span mc2rofs; - if (mUseMC) { - labels = pc.inputs().get*>("labels"); - // get the array as read-onlt span, a snapshot is send forward - mc2rofs = pc.inputs().get>("MC2ROframes"); - } - TimeFrame mTimeFrame; - mTimeFrame.setMemoryPool(mMemoryPool); - - LOG(info) << "ITSCookedTracker pulled " << compClusters.size() << " clusters, in " << rofs.size() << " RO frames"; - - std::vector trackLabels; - if (mUseMC) { - mTracker.setMCTruthContainers(labels.get(), &trackLabels); - } - - mVertexerPtr->adoptTimeFrame(mTimeFrame); - - auto& vertROFvec = pc.outputs().make>(Output{"ITS", "VERTICESROF", 0}); - auto& vertices = pc.outputs().make>(Output{"ITS", "VERTICES", 0}); - auto& tracks = pc.outputs().make>(Output{"ITS", "TRACKS", 0}); - auto& clusIdx = pc.outputs().make>(Output{"ITS", "TRACKCLSID", 0}); - auto& irFrames = pc.outputs().make>(Output{"ITS", "IRFRAMES", 0}); - - const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); // RS: this should come from CCDB - int nBCPerTF = mTracker.getContinuousMode() ? alpParams.roFrameLengthInBC : alpParams.roFrameLengthTrig; - - gsl::span::iterator pattIt_timeframe = patterns.begin(); - gsl::span::iterator pattIt_tracker = patterns.begin(); - gsl::span rofspan(rofs); - mTimeFrame.loadROFrameData(rofspan, compClusters, pattIt_timeframe, mDict, labels.get()); - - const auto& multEstConf = FastMultEstConfig::Instance(); // parameters for mult estimation and cuts - FastMultEst multEst; // mult estimator - std::vector processingMask; - int cutVertexMult{0}, cutRandomMult = int(rofsinput.size()) - multEst.selectROFs(rofsinput, compClusters, physTriggers, processingMask); - - // auto processingMask_ephemeral = processingMask; - mTimeFrame.setMultiplicityCutMask(processingMask); - float vertexerElapsedTime; - if (mRunVertexer) { - vertexerElapsedTime = mVertexerPtr->clustersToVertices([&](std::string s) { LOG(info) << s; }); - } - LOG(info) << fmt::format(" - Vertex seeding total elapsed time: {} ms in {} ROFs", vertexerElapsedTime, rofspan.size()); - for (size_t iRof{0}; iRof < rofspan.size(); ++iRof) { - auto& rof = rofspan[iRof]; - - auto& vtxROF = vertROFvec.emplace_back(rof); // register entry and number of vertices in the - vtxROF.setFirstEntry(vertices.size()); - vtxROF.setNEntries(0); - if (!processingMask[iRof]) { - rof.setFirstEntry(tracks.size()); - rof.setNEntries(0); - continue; - } - - std::vector>> vtxVecLoc; - for (auto& v : mTimeFrame.getPrimaryVertices(iRof)) { - vtxVecLoc.push_back(v); - } - - if (multEstConf.isVtxMultCutRequested()) { // cut was requested - std::vector>> vtxVecSel; - vtxVecSel.swap(vtxVecLoc); - int nv = vtxVecSel.size(), nrej = 0; - for (const auto& vtx : vtxVecSel) { - if (!multEstConf.isPassingVtxMultCut(vtx.getNContributors())) { - LOG(info) << "Found vertex mult. " << vtx.getNContributors() << " is outside of requested range " << multEstConf.cutMultVtxLow << " : " << multEstConf.cutMultVtxHigh << " | ROF " << rof.getBCData(); - nrej++; - continue; // skip vertex of unwanted multiplicity - } - vtxVecLoc.push_back(vtx); - } - if (nv && (nrej == nv)) { // all vertices were rejected - cutVertexMult++; - processingMask[iRof] = false; - } - } - if (vtxVecLoc.empty()) { - if (multEstConf.cutMultVtxLow < 1) { // do blind search only if there is no cut on the low mult vertices - vtxVecLoc.emplace_back(); - } else { - rof.setFirstEntry(tracks.size()); - rof.setNEntries(0); - continue; - } - } else { // save vertices - vtxROF.setNEntries(vtxVecLoc.size()); - for (const auto& vtx : vtxVecLoc) { - vertices.push_back(vtx); - } - } - - mTracker.setVertices(vtxVecLoc); - mTracker.process(compClusters, pattIt_tracker, mDict, tracks, clusIdx, rof); - if (processingMask[iRof]) { - irFrames.emplace_back(rof.getBCData(), rof.getBCData() + nBCPerTF - 1).info = tracks.size(); - } - } - LOGP(info, " - rejected {}/{} ROFs: random/mult.sel:{} (seed {}), vtx.sel:{}", cutRandomMult + cutVertexMult, rofspan.size(), cutRandomMult, multEst.lastRandomSeed, cutVertexMult); - LOG(info) << "ITSCookedTracker pushed " << tracks.size() << " tracks and " << vertices.size() << " vertices"; - - if (mUseMC) { - pc.outputs().snapshot(Output{"ITS", "TRACKSMCTR", 0}, trackLabels); - pc.outputs().snapshot(Output{"ITS", "ITSTrackMC2ROF", 0}, mc2rofs); - } - mTimer.Stop(); -} - -void CookedTrackerDPL::endOfStream(EndOfStreamContext& ec) -{ - LOGF(info, "ITS Cooked-Tracker total timing: Cpu: %.3e Real: %.3e s in %d slots", - mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); -} - -///_______________________________________ -void CookedTrackerDPL::updateTimeDependentParams(ProcessingContext& pc) -{ - o2::base::GRPGeomHelper::instance().checkUpdates(pc); - static bool initOnceDone = false; - if (!initOnceDone) { // this params need to be queried only once - initOnceDone = true; - pc.inputs().get("cldict"); // just to trigger the finaliseCCDB - pc.inputs().get*>("alppar"); - if (pc.inputs().getPos("itsTGeo") >= 0) { - pc.inputs().get("itsTGeo"); - } - mVertexerPtr->setParameters(TrackingMode::getVertexingParameters(mMode)); - o2::its::GeometryTGeo* geom = o2::its::GeometryTGeo::Instance(); - geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, - o2::math_utils::TransformType::T2G)); - mTracker.setGeometry(geom); - mTracker.setConfigParams(); - LOG(info) << "Tracking mode " << TrackingMode::toString(mMode); - if (mMode == TrackingMode::Cosmics) { - LOG(info) << "Setting cosmics parameters..."; - mTracker.setParametersCosmics(); - mRunVertexer = false; - } - mTracker.setBz(o2::base::Propagator::Instance()->getNominalBz()); - bool continuous = o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::ITS); - LOG(info) << "ITSCookedTracker RO: continuous=" << continuous; - mTracker.setContinuousMode(continuous); - } -} - -///_______________________________________ -void CookedTrackerDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) -{ - if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { - return; - } - if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) { - LOG(info) << "cluster dictionary updated"; - setClusterDictionary((const o2::itsmft::TopologyDictionary*)obj); - return; - } - // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level - if (matcher == ConcreteDataMatcher("ITS", "ALPIDEPARAM", 0)) { - LOG(info) << "Alpide param updated"; - const auto& par = o2::itsmft::DPLAlpideParam::Instance(); - par.printKeyValues(); - return; - } - if (matcher == ConcreteDataMatcher("ITS", "GEOMTGEO", 0)) { - LOG(info) << "ITS GeometryTGeo loaded from ccdb"; - o2::its::GeometryTGeo::adopt((o2::its::GeometryTGeo*)obj); - return; - } -} - -DataProcessorSpec getCookedTrackerSpec(bool useMC, bool useGeom, int trgType, TrackingMode::Type trmode) -{ - std::vector inputs; - inputs.emplace_back("compClusters", "ITS", "COMPCLUSTERS", 0, Lifetime::Timeframe); - inputs.emplace_back("patterns", "ITS", "PATTERNS", 0, Lifetime::Timeframe); - inputs.emplace_back("ROframes", "ITS", "CLUSTERSROF", 0, Lifetime::Timeframe); - inputs.emplace_back("cldict", "ITS", "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec("ITS/Calib/ClusterDictionary")); - inputs.emplace_back("alppar", "ITS", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/AlpideParam")); - if (trgType == 1) { - inputs.emplace_back("phystrig", "ITS", "PHYSTRIG", 0, Lifetime::Timeframe); - } else if (trgType == 2) { - inputs.emplace_back("phystrig", "TRD", "TRKTRGRD", 0, Lifetime::Timeframe); - } - - std::vector outputs; - outputs.emplace_back("ITS", "TRACKS", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "TRACKCLSID", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "ITSTrackROF", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "VERTICES", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "VERTICESROF", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "IRFRAMES", 0, Lifetime::Timeframe); - - if (useMC) { - inputs.emplace_back("labels", "ITS", "CLUSTERSMCTR", 0, Lifetime::Timeframe); - inputs.emplace_back("MC2ROframes", "ITS", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "TRACKSMCTR", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "ITSTrackMC2ROF", 0, Lifetime::Timeframe); - } - auto ggRequest = std::make_shared(false, // orbitResetTime - true, // GRPECS=true - false, // GRPLHCIF - true, // GRPMagField - true, // askMatLUT - useGeom ? o2::base::GRPGeomRequest::Aligned : o2::base::GRPGeomRequest::None, // geometry - inputs, - true); - if (!useGeom) { - ggRequest->addInput({"itsTGeo", "ITS", "GEOMTGEO", 0, Lifetime::Condition, framework::ccdbParamSpec("ITS/Config/Geometry")}, inputs); - } - return DataProcessorSpec{ - "its-cooked-tracker", - inputs, - outputs, - AlgorithmSpec{adaptFromTask(ggRequest, - useMC, - trgType, - trmode)}, - Options{{"nthreads", VariantType::Int, 1, {"Number of threads"}}}}; -} - -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx index 368ca6909240f..60e28556716f2 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx @@ -15,7 +15,6 @@ #include "ITSWorkflow/ClustererSpec.h" #include "ITSWorkflow/ClusterWriterSpec.h" #include "ITSWorkflow/TrackerSpec.h" -#include "ITSWorkflow/CookedTrackerSpec.h" #include "ITSWorkflow/TrackWriterSpec.h" #include "ITStracking/TrackingConfigParam.h" #include "ITSMFTWorkflow/DigitReaderSpec.h" @@ -29,7 +28,6 @@ namespace o2::its::reco_workflow { framework::WorkflowSpec getWorkflow(bool useMC, - bool useCMtracker, TrackingMode::Type trmode, const bool overrideBeamPosition, bool upstreamDigits, @@ -51,40 +49,36 @@ framework::WorkflowSpec getWorkflow(bool useMC, specs.emplace_back(o2::its::getClusterWriterSpec(useMC)); } if ((trmode != TrackingMode::Off) && (TrackerParamConfig::Instance().trackingMode != TrackingMode::Off)) { - if (useCMtracker) { - specs.emplace_back(o2::its::getCookedTrackerSpec(useMC, useGeom, useTrig, trmode)); - } else { - if (useGPUWF) { - o2::gpu::GPURecoWorkflowSpec::Config cfg{ - .itsTriggerType = useTrig, - .processMC = useMC, - .runITSTracking = true, - .itsOverrBeamEst = overrideBeamPosition, - }; + if (useGPUWF) { + o2::gpu::GPURecoWorkflowSpec::Config cfg{ + .itsTriggerType = useTrig, + .processMC = useMC, + .runITSTracking = true, + .itsOverrBeamEst = overrideBeamPosition, + }; - Inputs ggInputs; - auto ggRequest = std::make_shared(false, true, false, true, true, - useGeom ? o2::base::GRPGeomRequest::Aligned : o2::base::GRPGeomRequest::None, - ggInputs, true); - if (!useGeom) { - ggRequest->addInput({"itsTGeo", "ITS", "GEOMTGEO", 0, Lifetime::Condition, framework::ccdbParamSpec("ITS/Config/Geometry")}, ggInputs); - } + Inputs ggInputs; + auto ggRequest = std::make_shared(false, true, false, true, true, + useGeom ? o2::base::GRPGeomRequest::Aligned : o2::base::GRPGeomRequest::None, + ggInputs, true); + if (!useGeom) { + ggRequest->addInput({"itsTGeo", "ITS", "GEOMTGEO", 0, Lifetime::Condition, framework::ccdbParamSpec("ITS/Config/Geometry")}, ggInputs); + } - static std::vector policyData; - static std::shared_ptr task = std::make_shared(&policyData, cfg, std::vector(), 0, ggRequest); - Inputs taskInputs = task->inputs(); - Options taskOptions = task->options(); - std::move(ggInputs.begin(), ggInputs.end(), std::back_inserter(taskInputs)); + static std::vector policyData; + static std::shared_ptr task = std::make_shared(&policyData, cfg, std::vector(), 0, ggRequest); + Inputs taskInputs = task->inputs(); + Options taskOptions = task->options(); + std::move(ggInputs.begin(), ggInputs.end(), std::back_inserter(taskInputs)); - specs.emplace_back(DataProcessorSpec{ - .name = "its-gpu-tracker", - .inputs = taskInputs, - .outputs = task->outputs(), - .algorithm = AlgorithmSpec{adoptTask(task)}, - .options = taskOptions}); - } else { - specs.emplace_back(o2::its::getTrackerSpec(useMC, useGeom, useTrig, trmode, overrideBeamPosition, dtype)); - } + specs.emplace_back(DataProcessorSpec{ + .name = "its-gpu-tracker", + .inputs = taskInputs, + .outputs = task->outputs(), + .algorithm = AlgorithmSpec{adoptTask(task)}, + .options = taskOptions}); + } else { + specs.emplace_back(o2::its::getTrackerSpec(useMC, useGeom, useTrig, trmode, overrideBeamPosition, dtype)); } if (!disableRootOutput) { specs.emplace_back(o2::its::getTrackWriterSpec(useMC)); diff --git a/Detectors/ITSMFT/ITS/workflow/src/its-reco-workflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/its-reco-workflow.cxx index 4e1721f4194b0..8080883888d40 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/its-reco-workflow.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/its-reco-workflow.cxx @@ -41,8 +41,7 @@ void customize(std::vector& workflowOptions) {"clusters-from-upstream", o2::framework::VariantType::Bool, false, {"clusters will be provided from upstream, skip clusterizer"}}, {"disable-root-output", o2::framework::VariantType::Bool, false, {"do not write output root files"}}, {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}, - {"trackerCA", o2::framework::VariantType::Bool, false, {"use trackerCA (deprecated)"}}, // keep this around to not break scripts - {"trackerCM", o2::framework::VariantType::Bool, false, {"use trackerCM (default: trackerCA)"}}, + {"trackerCA", o2::framework::VariantType::Bool, false, {"use trackerCA (deprecated)"}}, // FIXME: keep this around to not break scripts {"ccdb-meanvertex-seed", o2::framework::VariantType::Bool, false, {"use MeanVertex from CCDB if available to provide beam position seed (default: false)"}}, {"select-with-triggers", o2::framework::VariantType::String, "none", {"use triggers to prescale processed ROFs: phys, trd, none"}}, {"tracking-mode", o2::framework::VariantType::String, "sync", {"sync,async,cosmics,unset,off"}}, @@ -65,7 +64,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // Update the (declared) parameters if changed from the command line auto useMC = !configcontext.options().get("disable-mc"); auto beamPosOVerride = configcontext.options().get("ccdb-meanvertex-seed"); - auto useCMtracker = configcontext.options().get("trackerCM"); auto trmode = configcontext.options().get("tracking-mode"); auto selTrig = configcontext.options().get("select-with-triggers"); auto useGpuWF = configcontext.options().get("use-gpu-workflow"); @@ -90,7 +88,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) } } auto wf = o2::its::reco_workflow::getWorkflow(useMC, - useCMtracker, o2::its::TrackingMode::fromString(trmode), beamPosOVerride, extDigits, diff --git a/macro/CMakeLists.txt b/macro/CMakeLists.txt index b5c51e50d3ffb..1c39a96db1b60 100644 --- a/macro/CMakeLists.txt +++ b/macro/CMakeLists.txt @@ -48,7 +48,6 @@ install(FILES CheckDigits_mft.C compareTOFClusters.C run_rawdecoding_its.C run_rawdecoding_mft.C - run_trac_its.C CreateBCPattern.C UploadDummyAlignment.C UploadMatBudLUT.C @@ -336,20 +335,6 @@ o2_add_test_root_macro(CreateCTPOrbitResetObject.C # O2::DataFormatsITSMFT O2::DataFormatsParameters O2::DetectorsBase O2::Field # O2::ITSBase O2::ITStracking O2::MathUtils O2::SimulationDataFormat) -# FIXME: move to subsystem dir -o2_add_test_root_macro(run_trac_its.C - PUBLIC_LINK_LIBRARIES O2::DetectorsCommonDataFormats - O2::DataFormatsITSMFT - O2::DataFormatsParameters - O2::DetectorsBase - O2::Field - O2::ITSBase - O2::ITSReconstruction - O2::ITStracking - O2::MathUtils - O2::SimulationDataFormat - LABELS its) - o2_add_test_root_macro(CreateGRPECSObject.C PUBLIC_LINK_LIBRARIES O2::DataFormatsParameters O2::DetectorsCommonDataFormats @@ -463,18 +448,6 @@ o2_add_test_root_macro(getTimeStamp.C # finished succesfully) set_tests_properties(run_clus_its_G3 PROPERTIES DEPENDS # run_digi_its_G3) -# configure_file(${CMAKE_SOURCE_DIR}/macro/run_trac_its.sh -# ${CMAKE_BINARY_DIR}/macro/run_trac_its.sh) -# configure_file(${CMAKE_SOURCE_DIR}/macro/run_trac_its.C -# ${CMAKE_BINARY_DIR}/macro/run_trac_its.C) - -# add_test_wrap(NAME run_trac_its_G3 COMMAND -# ${CMAKE_BINARY_DIR}/macro/run_trac_its.sh 10 TGeant3) -# set_tests_properties(run_trac_its_G3 PROPERTIES TIMEOUT 30) -# set_tests_properties(run_trac_its_G3 PROPERTIES PASS_REGULAR_EXPRESSION Macro -# finished succesfully) set_tests_properties(run_trac_its_G3 PROPERTIES DEPENDS -# run_clus_its_G3) - # #ITS tests with G4 # add_test_wrap(NAME run_sim_its_G4 COMMAND @@ -497,13 +470,6 @@ o2_add_test_root_macro(getTimeStamp.C # finished succesfully) set_tests_properties(run_clus_its_G4 PROPERTIES DEPENDS # run_digi_its_G4) -# add_test_wrap(NAME run_trac_its_G4 COMMAND -# ${CMAKE_BINARY_DIR}/macro/run_trac_its.sh 10 TGeant4) -# set_tests_properties(run_trac_its_G4 PROPERTIES TIMEOUT 30) -# set_tests_properties(run_trac_its_G4 PROPERTIES PASS_REGULAR_EXPRESSION Macro -# finished succesfully) set_tests_properties(run_trac_its_G4 PROPERTIES DEPENDS -# run_clus_its_G4) - # GENERATE_ROOT_TEST_SCRIPT(${CMAKE_SOURCE_DIR}/macro/load_all_libs.C) # add_test_wrap(load_all_libs ${CMAKE_BINARY_DIR}/macro/load_all_libs.sh) # Set_Tests_Properties(load_all_libs PROPERTIES TIMEOUT 30) diff --git a/macro/run_trac_its.C b/macro/run_trac_its.C deleted file mode 100644 index 824e4ebcf5d79..0000000000000 --- a/macro/run_trac_its.C +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#if !defined(__CLING__) || defined(__ROOTCLING__) -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include "Framework/Logger.h" -#include "DetectorsCommonDataFormats/DetID.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "DataFormatsParameters/GRPObject.h" -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsBase/Propagator.h" -#include "Field/MagneticField.h" -#include "ITSBase/GeometryTGeo.h" -#include "ITSReconstruction/CookedTracker.h" -#include "MathUtils/Utils.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "ReconstructionDataFormats/Vertex.h" -#include "DetectorsCommonDataFormats/DetectorNameConf.h" -#include "CCDB/BasicCCDBManager.h" -#include "CCDB/CCDBTimeStampUtils.h" -#include "DataFormatsITSMFT/TopologyDictionary.h" - -#include "ReconstructionDataFormats/PrimaryVertex.h" // hack to silence JIT compiler -#include "ITStracking/ROframe.h" -#include "ITStracking/IOUtils.h" -#include "ITStracking/Vertexer.h" -#include "ITStracking/VertexerTraits.h" - -using MCLabCont = o2::dataformats::MCTruthContainer; -using MCLabContTr = std::vector; -using Vertex = o2::dataformats::Vertex>; - -void run_trac_its(std::string path = "./", std::string outputfile = "o2trac_its.root", - std::string inputClustersITS = "o2clus_its.root", - std::string inputGeom = "", - std::string inputGRP = "o2sim_grp.root", - long timestamp = 0) -{ - - // Setup timer - TStopwatch timer; - - if (path.back() != '/') { - path += '/'; - } - - //-------- init geometry and field --------// - const auto grp = o2::parameters::GRPObject::loadFrom(path + inputGRP); - if (!grp) { - LOG(fatal) << "Cannot run w/o GRP object"; - } - bool isITS = grp->isDetReadOut(o2::detectors::DetID::ITS); - if (!isITS) { - LOG(warning) << "ITS is not in the readoute"; - return; - } - bool isContITS = grp->isDetContinuousReadOut(o2::detectors::DetID::ITS); - LOG(info) << "ITS is in " << (isContITS ? "CONTINUOS" : "TRIGGERED") << " readout mode"; - - o2::base::GeometryManager::loadGeometry(inputGeom); - auto gman = o2::its::GeometryTGeo::Instance(); - gman->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2GRot)); // request cached transforms - - o2::base::Propagator::initFieldFromGRP(grp); - auto field = static_cast(TGeoGlobalMagField::Instance()->GetField()); - if (!field) { - LOG(fatal) << "Failed to load ma"; - } - - auto& mgr = o2::ccdb::BasicCCDBManager::instance(); - mgr.setURL("http://alice-ccdb.cern.ch"); - mgr.setTimestamp(timestamp ? timestamp : o2::ccdb::getCurrentTimestamp()); - const o2::itsmft::TopologyDictionary* dict = mgr.get("ITS/Calib/ClusterDictionary"); - - //>>>---------- attach input data --------------->>> - TChain itsClusters("o2sim"); - itsClusters.AddFile((path + inputClustersITS).data()); - - if (!itsClusters.GetBranch("ITSClusterComp")) { - LOG(fatal) << "Did not find ITS clusters branch ITSClusterComp in the input tree"; - } - std::vector* cclusters = nullptr; - itsClusters.SetBranchAddress("ITSClusterComp", &cclusters); - - if (!itsClusters.GetBranch("ITSClusterPatt")) { - LOG(fatal) << "Did not find ITS cluster patterns branch ITSClusterPatt in the input tree"; - } - std::vector* patterns = nullptr; - itsClusters.SetBranchAddress("ITSClusterPatt", &patterns); - - MCLabCont* labels = nullptr; - if (!itsClusters.GetBranch("ITSClusterMCTruth")) { - LOG(warning) << "Did not find ITS clusters branch ITSClusterMCTruth in the input tree"; - } else { - itsClusters.SetBranchAddress("ITSClusterMCTruth", &labels); - } - - if (!itsClusters.GetBranch("ITSClustersROF")) { - LOG(fatal) << "Did not find ITS clusters branch ITSClustersROF in the input tree"; - } - - std::vector* mc2rofs = nullptr; - if (!itsClusters.GetBranch("ITSClustersMC2ROF")) { - LOG(warning) << "Did not find ITSClustersMC2ROF branch in the input tree"; - } - itsClusters.SetBranchAddress("ITSClustersMC2ROF", &mc2rofs); - - std::vector* rofs = nullptr; - itsClusters.SetBranchAddress("ITSClustersROF", &rofs); - - //>>>--------- create/attach output ------------->>> - // create/attach output tree - TFile outFile((path + outputfile).data(), "recreate"); - TTree outTree("o2sim", "Cooked ITS Tracks"); - std::vector tracksITS, *tracksITSPtr = &tracksITS; - std::vector trackClIdx, *trackClIdxPtr = &trackClIdx; - std::vector vertROFvec, *vertROFvecPtr = &vertROFvec; - std::vector vertices, *verticesPtr = &vertices; - - MCLabContTr trackLabels, *trackLabelsPtr = &trackLabels; - outTree.Branch("ITSTrack", &tracksITSPtr); - outTree.Branch("ITSTrackClusIdx", &trackClIdxPtr); - outTree.Branch("ITSTrackMCTruth", &trackLabelsPtr); - outTree.Branch("ITSTracksROF", &rofs); - outTree.Branch("ITSTracksMC2ROF", &mc2rofs); - outTree.Branch("Vertices", &verticesPtr); - outTree.Branch("VerticesROF", &vertROFvecPtr); - //<<<--------- create/attach output -------------<<< - - //=================== INIT ================== - Int_t n = 1; // Number of threads - Bool_t mcTruth = kTRUE; // kFALSE if no comparison with MC is needed - o2::its::CookedTracker tracker(n); - tracker.setContinuousMode(isContITS); - tracker.setBz(field->solenoidField()); // in kG - tracker.setGeometry(gman); - if (mcTruth) { - tracker.setMCTruthContainers(labels, trackLabelsPtr); - } - //=========================================== - - o2::its::VertexerTraits vertexerTraits; - o2::its::Vertexer vertexer(&vertexerTraits); - - int nTFs = itsClusters.GetEntries(); - for (int nt = 0; nt < nTFs; nt++) { - LOGP(info, "Processing timeframe {}/{}", nt, nTFs); - itsClusters.GetEntry(nt); - o2::its::TimeFrame tf; - gsl::span rofspan(*rofs); - gsl::span patt(*patterns); - - auto pattIt = patt.begin(); - auto pattIt_vertexer = patt.begin(); - auto clSpan = gsl::span(cclusters->data(), cclusters->size()); - std::vector processingMask(rofs->size(), true); - tf.loadROFrameData(rofspan, clSpan, pattIt_vertexer, dict, labels); - tf.setMultiplicityCutMask(processingMask); - vertexer.adoptTimeFrame(tf); - vertexer.clustersToVertices(); - int iRof = 0; - for (auto& rof : *rofs) { - auto it = pattIt; - - auto& vtxROF = vertROFvec.emplace_back(rof); // register entry and number of vertices in the - vtxROF.setFirstEntry(vertices.size()); // dedicated ROFRecord - std::vector>> verticesL; - vtxROF.setNEntries(tf.getPrimaryVertices(iRof).size()); - - for (const auto& vtx : tf.getPrimaryVertices(iRof)) { - vertices.push_back(vtx); - verticesL.push_back(vtx); - } - if (tf.getPrimaryVertices(iRof).empty()) { - verticesL.emplace_back(); - } - tracker.setVertices(verticesL); - tracker.process(clSpan, it, dict, tracksITS, trackClIdx, rof); - ++iRof; - } - outTree.Fill(); - if (mcTruth) { - trackLabelsPtr->clear(); - mc2rofs->clear(); - } - tracksITSPtr->clear(); - trackClIdxPtr->clear(); - rofs->clear(); - verticesPtr->clear(); - vertROFvecPtr->clear(); - } - outFile.cd(); - outTree.Write(); - outFile.Close(); - - timer.Stop(); - timer.Print(); -} - -#endif From f088a3566139cb874dcf01f0fea37627f2ec2e16 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Mon, 10 Nov 2025 10:27:16 +0100 Subject: [PATCH 065/234] ITS: remove old ClustererTask Signed-off-by: Felix Schlepper --- .../ITSMFT/ITS/reconstruction/CMakeLists.txt | 6 +- .../include/ITSReconstruction/ClustererTask.h | 85 --------- .../ITS/reconstruction/src/ClustererTask.cxx | 163 ------------------ macro/CMakeLists.txt | 9 - macro/run_clus_itsSA.C | 65 ------- 5 files changed, 2 insertions(+), 326 deletions(-) delete mode 100644 Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/ClustererTask.h delete mode 100644 Detectors/ITSMFT/ITS/reconstruction/src/ClustererTask.cxx delete mode 100644 macro/run_clus_itsSA.C diff --git a/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt b/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt index a5004418599e4..d2126be1da2c6 100644 --- a/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/reconstruction/CMakeLists.txt @@ -10,8 +10,7 @@ # or submit itself to any jurisdiction. o2_add_library(ITSReconstruction - SOURCES src/ClustererTask.cxx - src/RecoGeomHelper.cxx + SOURCES src/RecoGeomHelper.cxx src/FastMultEstConfig.cxx src/FastMultEst.cxx PUBLIC_LINK_LIBRARIES O2::ITSBase @@ -21,7 +20,6 @@ o2_add_library(ITSReconstruction o2_target_root_dictionary( ITSReconstruction - HEADERS include/ITSReconstruction/ClustererTask.h - include/ITSReconstruction/RecoGeomHelper.h + HEADERS include/ITSReconstruction/RecoGeomHelper.h include/ITSReconstruction/FastMultEst.h include/ITSReconstruction/FastMultEstConfig.h) diff --git a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/ClustererTask.h b/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/ClustererTask.h deleted file mode 100644 index 16ac9dd63c631..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/include/ITSReconstruction/ClustererTask.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ClustererTask.h -/// \brief Definition of the ITS cluster finder task - -#ifndef ALICEO2_ITS_CLUSTERERTASK -#define ALICEO2_ITS_CLUSTERERTASK - -#include "ITSMFTReconstruction/ChipMappingITS.h" -#include "ITSMFTReconstruction/PixelReader.h" -#include "ITSMFTReconstruction/RawPixelReader.h" -#include "ITSMFTReconstruction/DigitPixelReader.h" -#include "ITSMFTReconstruction/Clusterer.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include -#include - -namespace o2 -{ -class MCCompLabel; -namespace dataformats -{ -template -class MCTruthContainer; -} - -namespace its -{ - -class ClustererTask -{ - using Clusterer = o2::itsmft::Clusterer; - using CompCluster = o2::itsmft::CompCluster; - using CompClusterExt = o2::itsmft::CompClusterExt; - using MCTruth = o2::dataformats::MCTruthContainer; - - public: - ClustererTask(bool useMC = true, bool raw = false); - ~ClustererTask(); - - void Init(); - Clusterer& getClusterer() { return mClusterer; } - void run(const std::string inpName, const std::string outName); - o2::itsmft::PixelReader* getReader() const { return (o2::itsmft::PixelReader*)mReader; } - - void writeTree(std::string basename, int i); - void setMaxROframe(int max) { maxROframe = max; } - int getMaxROframe() const { return maxROframe; } - - private: - int maxROframe = std::numeric_limits::max(); ///< maximal number of RO frames per a file - bool mRawDataMode = false; ///< input from raw data or MC digits - bool mUseMCTruth = true; ///< flag to use MCtruth if available - o2::itsmft::PixelReader* mReader = nullptr; ///< Pointer on the relevant Pixel reader - std::unique_ptr mReaderMC; ///< reader for MC data - std::unique_ptr> mReaderRaw; ///< reader for raw data - - Clusterer mClusterer; ///< Cluster finder - - std::vector mCompClus; //!< vector of compact clusters - - std::vector mROFRecVec; //!< vector of ROFRecord references - - MCTruth mClsLabels; //! MC labels - - std::vector mPatterns; - - ClassDefNV(ClustererTask, 2); -}; -} // namespace its -} // namespace o2 - -#endif /* ALICEO2_ITS_CLUSTERERTASK */ diff --git a/Detectors/ITSMFT/ITS/reconstruction/src/ClustererTask.cxx b/Detectors/ITSMFT/ITS/reconstruction/src/ClustererTask.cxx deleted file mode 100644 index fb4e4ac7b6fa2..0000000000000 --- a/Detectors/ITSMFT/ITS/reconstruction/src/ClustererTask.cxx +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ClustererTask.cxx -/// \brief Implementation of the ITS cluster finder task - -#include "DetectorsCommonDataFormats/DetID.h" -#include "ITSReconstruction/ClustererTask.h" -#include "MathUtils/Cartesian.h" -#include "MathUtils/Utils.h" -#include -#include -#include - -using namespace o2::its; - -//_____________________________________________________________________ -ClustererTask::ClustererTask(bool useMC, bool raw) : mRawDataMode(raw), - mUseMCTruth(useMC && (!raw)) -{ - LOG(info) << Class()->GetName() << ": MC digits mode: " << (mRawDataMode ? "OFF" : "ON") - << " | Use MCtruth: " << (mUseMCTruth ? "ON" : "OFF"); - - mClusterer.setNChips(o2::itsmft::ChipMappingITS::getNChips()); -} - -//_____________________________________________________________________ -ClustererTask::~ClustererTask() -{ - mCompClus.clear(); - mClsLabels.clear(); -} - -//_____________________________________________________________________ -void ClustererTask::Init() -{ - /// Inititializes the clusterer and connects input and output container - - if (mReader) { - return; // already initialized - } - - // create reader according to requested raw of MC mode - if (mRawDataMode) { - mReaderRaw = std::make_unique>(); - mReader = mReaderRaw.get(); - } else { // clusterizer of digits - mReaderMC = std::make_unique(); - mReader = mReaderMC.get(); - } - - mClusterer.print(); - - return; -} - -//_____________________________________________________________________ -void ClustererTask::run(const std::string inpName, const std::string outName) -{ - // standalone execution - Init(); // create reader, clusterer - - if (mRawDataMode) { - - mReaderRaw->openInput(inpName); - mClusterer.process(1, *mReaderRaw.get(), &mCompClus, &mPatterns, &mROFRecVec, nullptr); - - auto basename = outName.substr(0, outName.size() - sizeof("root")); - auto nFiles = int(mROFRecVec.size() / maxROframe); - int i = 0; - for (; i < nFiles; i++) { - writeTree(basename, i); - } - writeTree(basename, i); // The remainder - - } else { - - mReaderMC->openInput(inpName, o2::detectors::DetID("ITS")); - - TFile outFile(outName.data(), "new"); - if (!outFile.IsOpen()) { - LOG(fatal) << "Failed to open output file " << outName; - } - - TTree outTree("o2sim", "ITS Clusters"); - - auto compClusPtr = &mCompClus; - outTree.Branch("ITSClusterComp", &compClusPtr); - - auto rofRecVecPtr = &mROFRecVec; - outTree.Branch("ITSClustersROF", &rofRecVecPtr); - - auto clsLabelsPtr = &mClsLabels; - if (mUseMCTruth && mReaderMC->getDigitsMCTruth()) { - // digit labels are provided directly to clusterer - outTree.Branch("ITSClusterMCTruth", &clsLabelsPtr); - } else { - mUseMCTruth = false; - } - LOG(info) << Class()->GetName() << " | MCTruth: " << (mUseMCTruth ? "ON" : "OFF"); - - outTree.Branch("ITSClusterPatt", &mPatterns); - - std::vector mc2rof, *mc2rofPtr = &mc2rof; - if (mUseMCTruth) { - auto mc2rofOrig = mReaderMC->getMC2ROFRecords(); - mc2rof.reserve(mc2rofOrig.size()); - for (const auto& m2r : mc2rofOrig) { // clone from the span - mc2rof.push_back(m2r); - } - outTree.Branch("ITSClustersMC2ROF", mc2rofPtr); - } - - // loop over entries of the input tree - while (mReaderMC->readNextEntry()) { - mClusterer.process(1, *mReaderMC.get(), &mCompClus, &mPatterns, &mROFRecVec, &mClsLabels); - } - - outTree.Fill(); - outTree.Write(); - } - - mClusterer.clear(); -} - -void ClustererTask::writeTree(std::string basename, int i) -{ - auto name = basename + std::to_string(i) + ".root"; - TFile outFile(name.data(), "new"); - if (!outFile.IsOpen()) { - LOG(fatal) << "Failed to open output file " << name; - } - TTree outTree("o2sim", "ITS Clusters"); - - size_t max = (i + 1) * maxROframe; - auto lastf = (max < mROFRecVec.size()) ? mROFRecVec.begin() + max : mROFRecVec.end(); - std::vector rofRecBuffer(mROFRecVec.begin() + i * maxROframe, lastf); - std::vector* rofRecPtr = &rofRecBuffer; - outTree.Branch("ITSClustersROF", rofRecPtr); - - auto first = rofRecBuffer[0].getFirstEntry(); - auto last = rofRecBuffer.back().getFirstEntry() + rofRecBuffer.back().getNEntries(); - - std::vector compClusBuffer, *compClusPtr = &compClusBuffer; - compClusBuffer.assign(&mCompClus[first], &mCompClus[last]); - outTree.Branch("ITSClusterComp", &compClusPtr); - outTree.Branch("ITSClusterPatt", &mPatterns); - - for (auto& rof : rofRecBuffer) { - rof.setFirstEntry(rof.getFirstEntry() - first); - } - - outTree.Fill(); - outTree.Write(); -} diff --git a/macro/CMakeLists.txt b/macro/CMakeLists.txt index 1c39a96db1b60..0bb5650364b06 100644 --- a/macro/CMakeLists.txt +++ b/macro/CMakeLists.txt @@ -35,7 +35,6 @@ install(FILES CheckDigits_mft.C runTPCRefit.C run_CRUDataSkimming_its.C run_calib_tof.C - run_clus_itsSA.C run_clus_tof.C run_clus_tpc.C run_clus_emcal.C @@ -243,14 +242,6 @@ o2_add_test_root_macro(run_calib_tof.C O2::DetectorsBase O2::GlobalTracking) -# FIXME: move to subsystem dir -o2_add_test_root_macro(run_clus_itsSA.C - PUBLIC_LINK_LIBRARIES O2::DetectorsBase - O2::ITSReconstruction - O2::ITSMFTReconstruction - O2::ITSMFTBase - LABELS its) - # FIXME: move to subsystem dir o2_add_test_root_macro(run_clus_tof.C PUBLIC_LINK_LIBRARIES O2::TOFReconstruction O2::Framework O2::TOFBase diff --git a/macro/run_clus_itsSA.C b/macro/run_clus_itsSA.C deleted file mode 100644 index a96cd66d5eeec..0000000000000 --- a/macro/run_clus_itsSA.C +++ /dev/null @@ -1,65 +0,0 @@ -#if !defined(__CLING__) || defined(__ROOTCLING__) -#include -#include "DetectorsBase/GeometryManager.h" -#include "ITSReconstruction/ClustererTask.h" -#include "ITSMFTReconstruction/Clusterer.h" -#include "ITSMFTBase/DPLAlpideParam.h" -#include "CommonConstants/LHCConstants.h" -#include "DetectorsCommonDataFormats/DetectorNameConf.h" -#include -#include "CCDB/BasicCCDBManager.h" -#include "CCDB/CCDBTimeStampUtils.h" -#endif - -// Clusterization avoiding FairRunAna management. -// Works both with MC digits and with "raw" data (in this case the last argument must be -// set to true). The raw data should be prepared beforeahand from the MC digits using e.g. -// o2::itsmft::RawPixelReader reader; -// reader.convertDigits2Raw("dig.raw","o2dig.root","o2sim","ITSDigit"); -// -// Use for MC mode: -// root -b -q run_clus_itsSA.C+\(\"o2clus_its.root\",\"o2dig.root\"\) 2>&1 | tee clusSA.log -// -// Use for RAW mode: -// root -b -q run_clus_itsSA.C+\(\"o2clus_its.root\",\"dig.raw\"\) 2>&1 | tee clusSARAW.log -// - -void run_clus_itsSA(std::string inputfile = "rawits.bin", // input file name - std::string outputfile = "clr.root", // output file name (root or raw) - bool raw = true, // flag if this is raw data - int strobeBC = -1, // strobe length in BC for masking, if <0, get automatically (assume cont. readout) - long timestamp = 0, - bool withPatterns = true) -{ - // Initialize logger - FairLogger* logger = FairLogger::GetLogger(); - logger->SetLogVerbosityLevel("LOW"); - logger->SetLogScreenLevel("INFO"); - - auto& mgr = o2::ccdb::BasicCCDBManager::instance(); - mgr.setURL("http://alice-ccdb.cern.ch"); - mgr.setTimestamp(timestamp ? timestamp : o2::ccdb::getCurrentTimestamp()); - const o2::itsmft::TopologyDictionary* dict = mgr.get("ITS/Calib/ClusterDictionary"); - - TStopwatch timer; - - // Setup clusterizer - Bool_t useMCTruth = kTRUE; // kFALSE if no comparison with MC needed - o2::its::ClustererTask* clus = new o2::its::ClustererTask(useMCTruth, raw); - clus->setMaxROframe(2 << 21); // about 3 cluster files per a raw data chunk - clus->getClusterer().setDictionary(dict); - - // Mask fired pixels separated by <= this number of BCs (for overflow pixels). - // In continuos mode strobe lenght should be used, in triggered one: signal shaping time (~7mus) - if (strobeBC < 0) { - const auto& dgParams = o2::itsmft::DPLAlpideParam::Instance(); - strobeBC = dgParams.roFrameLengthInBC; - } - clus->getClusterer().setMaxBCSeparationToMask(strobeBC + 10); - - clus->getClusterer().print(); - clus->run(inputfile, outputfile); - - timer.Stop(); - timer.Print(); -} From 4c3ba3d4518705622921f677129045ff25c380f4 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 8 Jan 2026 11:08:17 +0100 Subject: [PATCH 066/234] DPL: fix warnings --- Framework/Core/include/Framework/ServiceSpec.h | 2 +- Framework/Core/include/Framework/StringHelpers.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Framework/Core/include/Framework/ServiceSpec.h b/Framework/Core/include/Framework/ServiceSpec.h index 5684889e85376..8ac0872edd1bf 100644 --- a/Framework/Core/include/Framework/ServiceSpec.h +++ b/Framework/Core/include/Framework/ServiceSpec.h @@ -31,7 +31,7 @@ struct DeviceSpec; struct ServiceRegistry; struct ServiceRegistryRef; struct DeviceState; -struct ProcessingContext; +class ProcessingContext; class EndOfStreamContext; struct ConfigContext; struct WorkflowSpecNode; diff --git a/Framework/Core/include/Framework/StringHelpers.h b/Framework/Core/include/Framework/StringHelpers.h index 8a2d892062f70..a2ee758435efc 100644 --- a/Framework/Core/include/Framework/StringHelpers.h +++ b/Framework/Core/include/Framework/StringHelpers.h @@ -171,7 +171,7 @@ constexpr auto get_str(const char (&str)[N]) } template -constexpr auto get_size(const char (&str)[N]) +constexpr auto get_size(const char (&)[N]) { return N; } From 96e2f45f8c95c91f81b063e9ce35ad056b257fe9 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 8 Jan 2026 11:08:17 +0100 Subject: [PATCH 067/234] DPL: avoid MessageSet abstractions when forwarding This is most likely faster, and it will allow us to move the early forwarding at an earlier stage where the data is not yet in a MessageSet. --- .../include/Framework/DataProcessingHelpers.h | 9 +- Framework/Core/src/DataProcessingDevice.cxx | 2 +- Framework/Core/src/DataProcessingHelpers.cxx | 188 ++++++++++-------- Framework/Core/test/test_ForwardInputs.cxx | 27 ++- 4 files changed, 127 insertions(+), 99 deletions(-) diff --git a/Framework/Core/include/Framework/DataProcessingHelpers.h b/Framework/Core/include/Framework/DataProcessingHelpers.h index 34bb87613d920..a9bd95b69f4c7 100644 --- a/Framework/Core/include/Framework/DataProcessingHelpers.h +++ b/Framework/Core/include/Framework/DataProcessingHelpers.h @@ -16,6 +16,7 @@ #include "Framework/TimesliceIndex.h" #include #include +#include namespace o2::framework { @@ -53,9 +54,11 @@ struct DataProcessingHelpers { /// starts the EoS timers and returns the new TransitionHandlingState in case as new state is requested static TransitionHandlingState updateStateTransition(ServiceRegistryRef const& ref, ProcessingPolicies const& policies); /// Helper to route messages for forwarding - static std::vector routeForwardedMessages(FairMQDeviceProxy& proxy, - std::vector& currentSetOfInputs, - const bool copyByDefault, bool consume); + static std::vector routeForwardedMessageSet(FairMQDeviceProxy& proxy, std::vector& currentSetOfInputs, + bool copy, bool consume); + /// Helper to route messages for forwarding + static void routeForwardedMessages(FairMQDeviceProxy& proxy, std::span& currentSetOfInputs, std::vector& forwardedParts, + bool copy, bool consume); }; } // namespace o2::framework #endif // O2_FRAMEWORK_DATAPROCESSINGHELPERS_H_ diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index 63c333561f24e..3925359b056b2 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -592,7 +592,7 @@ static auto forwardInputs = [](ServiceRegistryRef registry, TimesliceSlot slot, O2_SIGNPOST_ID_GENERATE(sid, forwarding); O2_SIGNPOST_START(forwarding, sid, "forwardInputs", "Starting forwarding for slot %zu with oldestTimeslice %zu %{public}s%{public}s%{public}s", slot.index, oldestTimeslice.timeslice.value, copy ? "with copy" : "", copy && consume ? " and " : "", consume ? "with consume" : ""); - auto forwardedParts = DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copy, consume); + auto forwardedParts = DataProcessingHelpers::routeForwardedMessageSet(proxy, currentSetOfInputs, copy, consume); for (int fi = 0; fi < proxy.getNumForwardChannels(); fi++) { if (forwardedParts[fi].Size() == 0) { diff --git a/Framework/Core/src/DataProcessingHelpers.cxx b/Framework/Core/src/DataProcessingHelpers.cxx index 90dcee52d73da..2f7a1f65f3bd3 100644 --- a/Framework/Core/src/DataProcessingHelpers.cxx +++ b/Framework/Core/src/DataProcessingHelpers.cxx @@ -228,102 +228,128 @@ TransitionHandlingState DataProcessingHelpers::updateStateTransition(ServiceRegi } } -auto DataProcessingHelpers::routeForwardedMessages(FairMQDeviceProxy& proxy, - std::vector& currentSetOfInputs, - const bool copyByDefault, bool consume) -> std::vector +void DataProcessingHelpers::routeForwardedMessages(FairMQDeviceProxy& proxy, std::span& messages, std::vector& forwardedParts, + const bool copyByDefault, bool consume) { - // we collect all messages per forward in a map and send them together - std::vector forwardedParts; - forwardedParts.resize(proxy.getNumForwards()); - std::vector forwardingChoices{}; O2_SIGNPOST_ID_GENERATE(sid, forwarding); + std::vector forwardingChoices{}; + size_t pi = 0; + while (pi < messages.size()) { + auto& header = messages[pi]; - for (size_t ii = 0, ie = currentSetOfInputs.size(); ii < ie; ++ii) { - auto& messageSet = currentSetOfInputs[ii]; + // If is now possible that the record is not complete when + // we forward it, because of a custom completion policy. + // this means that we need to skip the empty entries in the + // record for being forwarded. + if (header->GetData() == nullptr) { + pi += 2; + continue; + } + auto dih = o2::header::get(header->GetData()); + if (dih) { + pi += 2; + continue; + } + auto sih = o2::header::get(header->GetData()); + if (sih) { + pi += 2; + continue; + } - for (size_t pi = 0; pi < messageSet.size(); ++pi) { - auto& header = messageSet.header(pi); + auto dph = o2::header::get(header->GetData()); + auto dh = o2::header::get(header->GetData()); - // If is now possible that the record is not complete when - // we forward it, because of a custom completion policy. - // this means that we need to skip the empty entries in the - // record for being forwarded. - if (header->GetData() == nullptr) { - continue; - } - auto dih = o2::header::get(header->GetData()); - if (dih) { - continue; - } - auto sih = o2::header::get(header->GetData()); - if (sih) { - continue; - } + if (dph == nullptr || dh == nullptr) { + // Complain only if this is not an out-of-band message + LOGP(error, "Data is missing {}{}{}", + dph ? "DataProcessingHeader" : "", dph || dh ? "and" : "", dh ? "DataHeader" : ""); + pi += 2; + continue; + } - auto dph = o2::header::get(header->GetData()); - auto dh = o2::header::get(header->GetData()); + // At least one payload. + auto& payload = messages[pi + 1]; + // Calculate the number of messages which should be handled together + // all in one go. + size_t numberOfMessages = 0; + if (dh->splitPayloadParts > 0 && dh->splitPayloadParts == dh->splitPayloadIndex) { + // Sequence of (header, payload[0], ... , payload[splitPayloadParts - 1]) pairs belonging together. + numberOfMessages = dh->splitPayloadParts + 1; // one is for the header + } else { + // Sequence of splitPayloadParts (header, payload) pairs belonging together. + // In case splitPayloadParts = 0, we consider this as a single message pair + numberOfMessages = (dh->splitPayloadParts > 0 ? dh->splitPayloadParts : 1) * 2; + } - if (dph == nullptr || dh == nullptr) { - // Complain only if this is not an out-of-band message - LOGP(error, "Data is missing {}{}{}", - dph ? "DataProcessingHeader" : "", dph || dh ? "and" : "", dh ? "DataHeader" : ""); - continue; - } + if (payload.get() == nullptr && consume == true) { + // If the payload is not there, it means we already + // processed it with ConsumeExisiting. Therefore we + // need to do something only if this is the last consume. + header.reset(nullptr); + pi += numberOfMessages; + continue; + } - auto& payload = messageSet.payload(pi); + // We need to find the forward route only for the first + // part of a split payload. All the others will use the same. + // Therefore, we reset and recompute the forwarding choice: + // + // - If this is the first payload of a [header0][payload0][header0][payload1]... sequence, + // which is actually always created and handled together. Notice that in this + // case we have splitPayloadParts == splitPayloadIndex + // - If this is the first payload of a [header0][payload0][header1][payload1]... sequence + // belonging to the same multipart message (and therefore we are guaranteed that they + // need to be routed together). + // - If the message is not a multipart (splitPayloadParts 0) or has only one part + // - If it's a message of the kind [header0][payload1][payload2][payload3]... and therefore + // we will already use the same choice in the for loop below. + // - if (payload.get() == nullptr && consume == true) { - // If the payload is not there, it means we already - // processed it with ConsumeExisiting. Therefore we - // need to do something only if this is the last consume. - header.reset(nullptr); - continue; - } + forwardingChoices.clear(); + proxy.getMatchingForwardChannelIndexes(forwardingChoices, *dh, dph->startTime); - // We need to find the forward route only for the first - // part of a split payload. All the others will use the same. - // Therefore, we reset and recompute the forwarding choice: - // - // - If this is the first payload of a [header0][payload0][header0][payload1] sequence, - // which is actually always created and handled together - // - If the message is not a multipart (splitPayloadParts 0) or has only one part - // - If it's a message of the kind [header0][payload1][payload2][payload3]... and therefore - // we will already use the same choice in the for loop below. - if (dh->splitPayloadIndex == 0 || dh->splitPayloadParts <= 1 || messageSet.getNumberOfPayloads(pi) > 0) { - forwardingChoices.clear(); - proxy.getMatchingForwardChannelIndexes(forwardingChoices, *dh, dph->startTime); - } + if (forwardingChoices.empty()) { + // Nothing to forward go to the next messageset + pi += numberOfMessages; + continue; + } - if (forwardingChoices.empty()) { - // Nothing to forward go to the next messageset - continue; - } + // In case of more than one forward route, we need to copy the message. + // This will eventually use the same memory if running with the same backend. + if (copyByDefault || forwardingChoices.size() > 1) { + for (auto& choice : forwardingChoices) { + O2_SIGNPOST_EVENT_EMIT(forwarding, sid, "forwardInputs", "Forwarding a copy of %{public}s to route %d.", + fmt::format("{}/{}/{}@timeslice:{} tfCounter:{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification, dph->startTime, dh->tfCounter).c_str(), choice.value); - // In case of more than one forward route, we need to copy the message. - // This will eventually use the same memory if running with the same backend. - if (copyByDefault || forwardingChoices.size() > 1) { - for (auto& choice : forwardingChoices) { - auto&& newHeader = header->GetTransport()->CreateMessage(); - O2_SIGNPOST_EVENT_EMIT(forwarding, sid, "forwardInputs", "Forwarding a copy of %{public}s to route %d.", - fmt::format("{}/{}/{}@timeslice:{} tfCounter:{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification, dph->startTime, dh->tfCounter).c_str(), choice.value); - newHeader->Copy(*header); - forwardedParts[choice.value].AddPart(std::move(newHeader)); - - for (size_t payloadIndex = 0; payloadIndex < messageSet.getNumberOfPayloads(pi); ++payloadIndex) { - auto&& newPayload = header->GetTransport()->CreateMessage(); - newPayload->Copy(*messageSet.payload(pi, payloadIndex)); - forwardedParts[choice.value].AddPart(std::move(newPayload)); - } - } - } else { - O2_SIGNPOST_EVENT_EMIT(forwarding, sid, "forwardInputs", "Forwarding %{public}s to route %d.", - fmt::format("{}/{}/{}@timeslice:{} tfCounter:{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification, dph->startTime, dh->tfCounter).c_str(), forwardingChoices.back().value); - forwardedParts[forwardingChoices.back().value].AddPart(std::move(messageSet.header(pi))); - for (size_t payloadIndex = 0; payloadIndex < messageSet.getNumberOfPayloads(pi); ++payloadIndex) { - forwardedParts[forwardingChoices.back().value].AddPart(std::move(messageSet.payload(pi, payloadIndex))); + for (size_t ppi = pi; ppi < pi + numberOfMessages; ++ppi) { + auto&& newMsg = header->GetTransport()->CreateMessage(); + newMsg->Copy(*messages[ppi]); + forwardedParts[choice.value].AddPart(std::move(newMsg)); } } + } else { + O2_SIGNPOST_EVENT_EMIT(forwarding, sid, "forwardInputs", "Forwarding %{public}s to route %d.", + fmt::format("{}/{}/{}@timeslice:{} tfCounter:{}", dh->dataOrigin, dh->dataDescription, dh->subSpecification, dph->startTime, dh->tfCounter).c_str(), forwardingChoices.back().value); + for (size_t ppi = pi; ppi < pi + numberOfMessages; ++ppi) { + forwardedParts[forwardingChoices.back().value].AddPart(std::move(messages[ppi])); + } } + pi += numberOfMessages; + } +} + +auto DataProcessingHelpers::routeForwardedMessageSet(FairMQDeviceProxy& proxy, + std::vector& currentSetOfInputs, + const bool copyByDefault, bool consume) -> std::vector +{ + // we collect all messages per forward in a map and send them together + std::vector forwardedParts; + forwardedParts.resize(proxy.getNumForwards()); + std::vector forwardingChoices{}; + + for (size_t ii = 0, ie = currentSetOfInputs.size(); ii < ie; ++ii) { + auto span = std::span(currentSetOfInputs[ii].messages); + routeForwardedMessages(proxy, span, forwardedParts, copyByDefault, consume); } return forwardedParts; }; diff --git a/Framework/Core/test/test_ForwardInputs.cxx b/Framework/Core/test/test_ForwardInputs.cxx index 7ddbc831edad2..fe9f70d1daadb 100644 --- a/Framework/Core/test/test_ForwardInputs.cxx +++ b/Framework/Core/test/test_ForwardInputs.cxx @@ -45,7 +45,7 @@ TEST_CASE("ForwardInputsEmpty") std::vector currentSetOfInputs; - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.empty()); } @@ -95,7 +95,7 @@ TEST_CASE("ForwardInputsSingleMessageSingleRoute") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 1); // One route REQUIRE(result[0].Size() == 2); // Two messages for that route } @@ -146,7 +146,7 @@ TEST_CASE("ForwardInputsSingleMessageSingleRouteNoConsume") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, true); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, currentSetOfInputs, copyByDefault, true); REQUIRE(result.size() == 1); REQUIRE(result[0].Size() == 0); // Because there is a nullptr, we do not forward this as it was already consumed. } @@ -201,8 +201,7 @@ TEST_CASE("ForwardInputsSingleMessageSingleRouteAtEOS") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 1); // One route REQUIRE(result[0].Size() == 0); // FIXME: this is an actual error. It should be 2. However it cannot really happen. // Correct behavior below: @@ -260,7 +259,7 @@ TEST_CASE("ForwardInputsSingleMessageSingleRouteWithOldestPossible") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 1); // One route REQUIRE(result[0].Size() == 0); // FIXME: this is actually wrong // FIXME: actually correct behavior below @@ -325,7 +324,7 @@ TEST_CASE("ForwardInputsSingleMessageMultipleRoutes") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 2); // Two routes REQUIRE(result[0].Size() == 2); // Two messages per route REQUIRE(result[1].Size() == 0); // Only the first DPL matched channel matters @@ -388,7 +387,7 @@ TEST_CASE("ForwardInputsSingleMessageMultipleRoutesExternals") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 2); // Two routes REQUIRE(result[0].Size() == 2); // With external matching channels, we need to copy and then forward REQUIRE(result[1].Size() == 2); // @@ -466,7 +465,7 @@ TEST_CASE("ForwardInputsMultiMessageMultipleRoutes") currentSetOfInputs.emplace_back(std::move(messageSet2)); REQUIRE(currentSetOfInputs.size() == 2); - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 2); // Two routes REQUIRE(result[0].Size() == 2); // REQUIRE(result[1].Size() == 2); // @@ -529,7 +528,7 @@ TEST_CASE("ForwardInputsSingleMessageMultipleRoutesOnlyOneMatches") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 2); // Two routes REQUIRE(result[0].Size() == 0); // Two messages per route REQUIRE(result[1].Size() == 2); // Two messages per route @@ -541,7 +540,7 @@ TEST_CASE("ForwardInputsSplitPayload") dh.dataOrigin = "TST"; dh.dataDescription = "A"; dh.subSpecification = 0; - dh.splitPayloadIndex = 0; + dh.splitPayloadIndex = 2; dh.splitPayloadParts = 2; o2::header::DataHeader dh2; @@ -611,7 +610,7 @@ TEST_CASE("ForwardInputsSplitPayload") REQUIRE(messageSet.size() == 2); currentSetOfInputs.emplace_back(std::move(messageSet)); - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 2); // Two routes CHECK(result[0].Size() == 2); // No messages on this route CHECK(result[1].Size() == 3); @@ -657,7 +656,7 @@ TEST_CASE("ForwardInputEOSSingleRoute") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 1); // One route REQUIRE(result[0].Size() == 0); // Oldest possible timeframe should not be forwarded } @@ -702,7 +701,7 @@ TEST_CASE("ForwardInputOldestPossibleSingleRoute") REQUIRE(messageSet.size() == 1); currentSetOfInputs.emplace_back(std::move(messageSet)); - auto result = o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, currentSetOfInputs, copyByDefault, consume); + auto result = o2::framework::DataProcessingHelpers::routeForwardedMessageSet(proxy, currentSetOfInputs, copyByDefault, consume); REQUIRE(result.size() == 1); // One route REQUIRE(result[0].Size() == 0); // Oldest possible timeframe should not be forwarded } From bf75199a5345651cad229244d1f0a3f38dbbdb92 Mon Sep 17 00:00:00 2001 From: Florian Jonas Date: Fri, 9 Jan 2026 16:18:37 +0100 Subject: [PATCH 068/234] [EMCAL] implementation of number of local maxima variable * [EMCAL] implementation of number of local maxima variable * Please consider the following formatting changes * further optimizations of EMCAL evalNExMax * Please consider the following formatting changes --------- Co-authored-by: ALICE Action Bot --- .../base/include/EMCALBase/ClusterFactory.h | 4 ++ .../EMCAL/base/include/EMCALBase/Geometry.h | 8 +++ Detectors/EMCAL/base/src/ClusterFactory.cxx | 60 +++++++++++++++++++ Detectors/EMCAL/base/src/Geometry.cxx | 24 ++++++++ 4 files changed, 96 insertions(+) diff --git a/Detectors/EMCAL/base/include/EMCALBase/ClusterFactory.h b/Detectors/EMCAL/base/include/EMCALBase/ClusterFactory.h index a7e81d38838a3..0c3438042ca77 100644 --- a/Detectors/EMCAL/base/include/EMCALBase/ClusterFactory.h +++ b/Detectors/EMCAL/base/include/EMCALBase/ClusterFactory.h @@ -401,6 +401,10 @@ class ClusterFactory /// in cell units void evalElipsAxis(gsl::span inputsIndices, AnalysisCluster& clusterAnalysis) const; + /// + /// Calculate the number of local maxima in the cluster + void evalNExMax(gsl::span inputsIndices, AnalysisCluster& clusterAnalysis) const; + /// /// Time is set to the time of the digit with the maximum energy void evalTime(gsl::span inputsIndices, AnalysisCluster& clusterAnalysis) const; diff --git a/Detectors/EMCAL/base/include/EMCALBase/Geometry.h b/Detectors/EMCAL/base/include/EMCALBase/Geometry.h index b4621d4b6e434..d07f42689bf7a 100644 --- a/Detectors/EMCAL/base/include/EMCALBase/Geometry.h +++ b/Detectors/EMCAL/base/include/EMCALBase/Geometry.h @@ -429,6 +429,14 @@ class Geometry /// \return Position (0 - phi, 1 - eta) of the cell inside teh supermodule std::tuple GetCellPhiEtaIndexInSModule(int supermoduleID, int moduleID, int phiInModule, int etaInModule) const; + /// \brief Get topological row and column of cell in SM (same as for clusteriser with artifical gaps) + /// \param supermoduleID super module number + /// \param moduleID module number + /// \param phiInModule index in phi direction in module + /// \param etaInModule index in phi direction in module + /// \return tuple with (row, column) of the cell, which is global numbering scheme + std::tuple GetTopologicalRowColumn(int supermoduleID, int moduleID, int phiInModule, int etaInModule) const; + /// \brief Adapt cell indices in supermodule to online indexing /// \param supermoduleID super module number of the channel/cell /// \param iphi row/phi cell index, modified for DCal diff --git a/Detectors/EMCAL/base/src/ClusterFactory.cxx b/Detectors/EMCAL/base/src/ClusterFactory.cxx index 342f54fd94591..970f7979ef86d 100644 --- a/Detectors/EMCAL/base/src/ClusterFactory.cxx +++ b/Detectors/EMCAL/base/src/ClusterFactory.cxx @@ -120,6 +120,9 @@ o2::emcal::AnalysisCluster ClusterFactory::buildCluster(int clusterIn evalElipsAxis(inputsIndices, clusterAnalysis); evalDispersion(inputsIndices, clusterAnalysis); + // evaluate number of local maxima + evalNExMax(inputsIndices, clusterAnalysis); + evalCoreEnergy(inputsIndices, clusterAnalysis); evalTime(inputsIndices, clusterAnalysis); @@ -489,6 +492,63 @@ void ClusterFactory::evalCoreEnergy(gsl::span inputsIndice clusterAnalysis.setCoreEnergy(coreEnergy); } +/// +/// Calculate the number of local maxima in the cluster +//____________________________________________________________________________ +template +void ClusterFactory::evalNExMax(gsl::span inputsIndices, AnalysisCluster& clusterAnalysis) const +{ + // Pre-compute cell indices and energies for all cells in cluster to avoid multiple expensive geometry lookups + const size_t n = inputsIndices.size(); + std::vector rows; + std::vector columns; + std::vector energies; + + rows.reserve(n); + columns.reserve(n); + energies.reserve(n); + + for (auto iInput : inputsIndices) { + auto [nSupMod, nModule, nIphi, nIeta] = mGeomPtr->GetCellIndex(mInputsContainer[iInput].getTower()); + + // get a nice topological indexing that is done in exactly the same way as used by the clusterizer + // this way we can handle the shared cluster cases correctly + const auto [row, column] = mGeomPtr->GetTopologicalRowColumn(nSupMod, nModule, nIphi, nIeta); + + rows.push_back(row); + columns.push_back(column); + energies.push_back(mInputsContainer[iInput].getEnergy()); + } + + // Now find local maxima using pre-computed data + int nExMax = 0; + for (size_t i = 0; i < n; i++) { + // this cell is assumed to be local maximum unless we find a higher energy cell in the neighborhood + bool isExMax = true; + + // loop over all other cells in cluster + for (size_t j = 0; j < n; j++) { + if (i == j) + continue; + + // adjacent cell is any cell with adjacent phi or eta index + if (std::abs(rows[i] - rows[j]) <= 1 && + std::abs(columns[i] - columns[j]) <= 1) { + + // if there is a cell with higher energy than the current cell, it is not a local maximum + if (energies[j] > energies[i]) { + isExMax = false; + break; + } + } + } + if (isExMax) { + nExMax++; + } + } + clusterAnalysis.setNExMax(nExMax); +} + /// /// Calculates the axis of the shower ellipsoid in eta and phi /// in cell units diff --git a/Detectors/EMCAL/base/src/Geometry.cxx b/Detectors/EMCAL/base/src/Geometry.cxx index c194f570e47d1..3707e22f2da57 100644 --- a/Detectors/EMCAL/base/src/Geometry.cxx +++ b/Detectors/EMCAL/base/src/Geometry.cxx @@ -1103,6 +1103,30 @@ std::tuple Geometry::GetCellPhiEtaIndexInSModule(int supermoduleID, in return std::make_tuple(phiInSupermodule, etaInSupermodule); } +std::tuple Geometry::GetTopologicalRowColumn(int supermoduleID, int moduleID, int phiInModule, int etaInModule) const +{ + auto [iphi, ieta] = GetCellPhiEtaIndexInSModule(supermoduleID, moduleID, phiInModule, etaInModule); + int row = iphi; + int column = ieta; + + // Add shifts wrt. supermodule and type of calorimeter + // NOTE: + // * Rows (phi) are arranged that one space is left empty between supermodules in phi + // This is due to the physical gap that forbids clustering + // * For DCAL, there is an additional empty column between two supermodules in eta + // Again, this is to account for the gap in DCAL + + row += supermoduleID / 2 * (24 + 1); + // In DCAL, leave a gap between two SMs with same phi + if (!IsDCALSM(supermoduleID)) { // EMCAL + column += supermoduleID % 2 * 48; + } else { + column += supermoduleID % 2 * (48 + 1); + } + + return std::make_tuple(static_cast(row), static_cast(column)); +} + std::tuple Geometry::ShiftOnlineToOfflineCellIndexes(Int_t supermoduleID, Int_t iphi, Int_t ieta) const { if (supermoduleID == 13 || supermoduleID == 15 || supermoduleID == 17) { From 696cf650cc142446b722e1b10212bfcc4d14f03d Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:39:02 +0100 Subject: [PATCH 069/234] DPL: fix a few warnings --- Framework/Core/include/Framework/GuiCallbackContext.h | 2 +- Framework/Core/include/Framework/InitContext.h | 2 +- Framework/Core/include/Framework/ServiceRegistry.h | 2 +- Framework/Core/include/Framework/ServiceSpec.h | 4 ++-- Framework/Core/src/TMessageSerializer.cxx | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Framework/Core/include/Framework/GuiCallbackContext.h b/Framework/Core/include/Framework/GuiCallbackContext.h index 1dbb6ec30e849..5bb3148621476 100644 --- a/Framework/Core/include/Framework/GuiCallbackContext.h +++ b/Framework/Core/include/Framework/GuiCallbackContext.h @@ -23,7 +23,7 @@ namespace o2::framework { struct GuiCallbackContext; -class WSDPLHandler; +struct WSDPLHandler; struct GuiRenderer { uv_timer_t drawTimer; diff --git a/Framework/Core/include/Framework/InitContext.h b/Framework/Core/include/Framework/InitContext.h index 8e616d276748b..7f6cec3c7a160 100644 --- a/Framework/Core/include/Framework/InitContext.h +++ b/Framework/Core/include/Framework/InitContext.h @@ -16,7 +16,7 @@ namespace o2::framework { -class ServiceRegistry; +struct ServiceRegistry; class ConfigParamRegistry; // This is a utility class to reduce the amount of boilerplate when defining diff --git a/Framework/Core/include/Framework/ServiceRegistry.h b/Framework/Core/include/Framework/ServiceRegistry.h index ebafd466929ff..d6516e31be62d 100644 --- a/Framework/Core/include/Framework/ServiceRegistry.h +++ b/Framework/Core/include/Framework/ServiceRegistry.h @@ -158,7 +158,7 @@ struct ServiceRegistry { /// not bonded to a specific stream, e.g. the /// name of the data processor, its inputs and outputs, /// it's algorithm. - static Salt dataProcessorSalt(short dataProcessorId) + static Salt dataProcessorSalt(short /* dataProcessorId */) { // FIXME: old behaviour for now // return {0, dataProcessorId}; diff --git a/Framework/Core/include/Framework/ServiceSpec.h b/Framework/Core/include/Framework/ServiceSpec.h index 8ac0872edd1bf..aa762b5d039e0 100644 --- a/Framework/Core/include/Framework/ServiceSpec.h +++ b/Framework/Core/include/Framework/ServiceSpec.h @@ -26,10 +26,10 @@ struct ProgOptions; namespace o2::framework { -struct InitContext; +class InitContext; struct DeviceSpec; struct ServiceRegistry; -struct ServiceRegistryRef; +class ServiceRegistryRef; struct DeviceState; class ProcessingContext; class EndOfStreamContext; diff --git a/Framework/Core/src/TMessageSerializer.cxx b/Framework/Core/src/TMessageSerializer.cxx index 81a1c6e537d09..bf9583f780957 100644 --- a/Framework/Core/src/TMessageSerializer.cxx +++ b/Framework/Core/src/TMessageSerializer.cxx @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include -#include +#include #include #include From 67c2a31833ceafdfb6a497b94ea1ae6be3f17651 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 6 Jan 2026 10:59:37 +0100 Subject: [PATCH 070/234] TPC: move PadFlags and related classes to TPCBaseRecSim o2::tpc::PadFlags and in particular vectors of thereof are affected by an old ROOT bug in serializing `std::vector`. Because of this we have a custom streamer which needs to be initialised very early in order to function correctly. This is fine, however, due to the fact we invoke `TClass::GetClass()` too early, ROOT is forced a bunch of extra stuff, unneededly, resulting in much increased memory footprint in analysis, which happens to use DataFormatsTPC. This makes sure the custom streamer is not initialised statically by DataFormatsTPC and prevents ROOT from loading the kitchen sink when the TClass::GetClass is invoked too early. --- .../TPC/include/DataFormatsTPC/Defs.h | 17 ------- .../Detectors/TPC/src/DataFormatsTPCLinkDef.h | 2 - Detectors/TPC/CMakeLists.txt | 1 + Detectors/TPC/base/CMakeLists.txt | 21 +-------- Detectors/TPC/base/src/TPCBaseLinkDef.h | 8 ---- .../TPC/base/test/testTPCCDBInterface.cxx | 2 +- Detectors/TPC/baserecsim/CMakeLists.txt | 35 +++++++++++++++ .../include/TPCBaseRecSim}/CDBInterface.h | 4 +- .../include/TPCBaseRecSim}/CDBTypes.h | 0 .../TPCBaseRecSim}/DeadChannelMapCreator.h | 4 +- .../include/TPCBaseRecSim/PadFlags.h | 44 +++++++++++++++++++ .../include/TPCBaseRecSim}/Painter.h | 0 .../{base => baserecsim}/src/CDBInterface.cxx | 2 +- .../src/DeadChannelMapCreator.cxx | 4 +- .../TPC/{base => baserecsim}/src/Painter.cxx | 3 +- .../TPC/baserecsim/src/TPCBaseRecSimLinkDef.h | 27 ++++++++++++ .../src/TPCFlagsMemberCustomStreamer.cxx | 0 .../test/testTPCCalDet.cxx | 2 +- Detectors/TPC/calibration/CMakeLists.txt | 10 ++--- .../include/TPCCalibration/IDCCCDBHelper.h | 1 + .../include/TPCCalibration/IDCFactorization.h | 1 + .../macro/comparePedestalsAndNoise.C | 4 +- .../calibration/macro/drawNoiseAndPedestal.C | 4 +- Detectors/TPC/calibration/macro/drawPulser.C | 2 +- .../TPC/calibration/macro/prepareCMFiles.C | 2 +- .../TPC/calibration/macro/prepareITFiles.C | 2 +- .../calibration/macro/preparePedestalFiles.C | 2 +- .../TPC/calibration/src/CalculatedEdx.cxx | 2 +- .../src/CalibPadGainTracksBase.cxx | 2 +- .../calibration/src/CorrectionMapsLoader.cxx | 2 +- .../TPC/calibration/src/IDCAverageGroup.cxx | 3 +- .../TPC/calibration/src/IDCCCDBHelper.cxx | 2 +- .../TPC/calibration/src/IDCDrawHelper.cxx | 2 +- .../src/PressureTemperatureHelper.cxx | 2 +- .../TPC/calibration/src/SACDrawHelper.cxx | 2 +- .../TPC/calibration/src/VDriftHelper.cxx | 2 +- Detectors/TPC/dcs/src/DCSConfigSpec.cxx | 2 +- Detectors/TPC/dcs/src/DCSSpec.cxx | 2 +- .../TPC/monitor/src/SimpleEventDisplayGUI.cxx | 2 +- Detectors/TPC/qc/macro/runClusters.C | 2 +- Detectors/TPC/qc/macro/runPID.C | 2 +- Detectors/TPC/qc/src/Clusters.cxx | 2 +- Detectors/TPC/qc/src/IDCsVsSACs.cxx | 2 +- Detectors/TPC/simulation/macro/toyCluster.C | 2 +- .../TPC/simulation/src/DigitContainer.cxx | 2 +- Detectors/TPC/simulation/src/Digitizer.cxx | 2 +- .../TPC/simulation/src/ElectronTransport.cxx | 2 +- .../TPC/simulation/src/GEMAmplification.cxx | 2 +- Detectors/TPC/simulation/src/IDCSim.cxx | 2 +- .../TPC/simulation/src/SAMPAProcessing.cxx | 2 +- .../simulation/test/testTPCDigitContainer.cxx | 2 +- .../test/testTPCElectronTransport.cxx | 2 +- .../test/testTPCGEMAmplification.cxx | 2 +- .../test/testTPCSAMPAProcessing.cxx | 2 +- Detectors/TPC/spacecharge/CMakeLists.txt | 2 +- .../macro/createSCHistosFromHits.C | 2 +- Detectors/TPC/spacecharge/src/SpaceCharge.cxx | 2 +- .../TPCWorkflow/CalibratorPadGainTracksSpec.h | 2 +- .../TPCWorkflow/TPCCalibPadGainTracksSpec.h | 2 +- .../include/TPCWorkflow/TPCCalibPadRawSpec.h | 2 +- .../include/TPCWorkflow/TPCFLPIDCSpec.h | 2 +- .../include/TPCWorkflow/TPCFactorizeIDCSpec.h | 2 +- .../include/TPCWorkflow/TPCFactorizeSACSpec.h | 2 +- .../src/CalDetMergerPublisherSpec.cxx | 2 +- Detectors/TPC/workflow/src/CalibdEdxSpec.cxx | 2 +- .../TPC/workflow/src/CalibratordEdxSpec.cxx | 2 +- .../TPC/workflow/src/SACProcessorSpec.cxx | 2 +- .../src/TPCMergeIntegrateClusterSpec.cxx | 2 +- Detectors/TPC/workflow/src/TPCScalerSpec.cxx | 2 +- GPU/Workflow/src/GPUWorkflowSpec.cxx | 4 +- GPU/Workflow/src/GPUWorkflowTPC.cxx | 4 +- .../src/SimpleDigitizerWorkflow.cxx | 2 +- .../src/TPCDigitizerSpec.cxx | 2 +- 73 files changed, 183 insertions(+), 118 deletions(-) create mode 100644 Detectors/TPC/baserecsim/CMakeLists.txt rename Detectors/TPC/{base/include/TPCBase => baserecsim/include/TPCBaseRecSim}/CDBInterface.h (99%) rename Detectors/TPC/{base/include/TPCBase => baserecsim/include/TPCBaseRecSim}/CDBTypes.h (100%) rename Detectors/TPC/{base/include/TPCBase => baserecsim/include/TPCBaseRecSim}/DeadChannelMapCreator.h (98%) create mode 100644 Detectors/TPC/baserecsim/include/TPCBaseRecSim/PadFlags.h rename Detectors/TPC/{base/include/TPCBase => baserecsim/include/TPCBaseRecSim}/Painter.h (100%) rename Detectors/TPC/{base => baserecsim}/src/CDBInterface.cxx (99%) rename Detectors/TPC/{base => baserecsim}/src/DeadChannelMapCreator.cxx (98%) rename Detectors/TPC/{base => baserecsim}/src/Painter.cxx (99%) create mode 100644 Detectors/TPC/baserecsim/src/TPCBaseRecSimLinkDef.h rename Detectors/TPC/{base => baserecsim}/src/TPCFlagsMemberCustomStreamer.cxx (100%) rename Detectors/TPC/{base => baserecsim}/test/testTPCCalDet.cxx (99%) diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/Defs.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/Defs.h index 9b8853a10535d..fa04586479a22 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/Defs.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/Defs.h @@ -97,23 +97,6 @@ enum class StatisticsType { MeanStdDev ///< Use mean and standard deviation }; -enum class PadFlags : unsigned short { - flagGoodPad = 1 << 0, ///< flag for a good pad binary 0001 - flagDeadPad = 1 << 1, ///< flag for a dead pad binary 0010 - flagUnknownPad = 1 << 2, ///< flag for unknown status binary 0100 - flagSaturatedPad = 1 << 3, ///< flag for saturated status binary 0100 - flagHighPad = 1 << 4, ///< flag for pad with extremly high IDC value - flagLowPad = 1 << 5, ///< flag for pad with extremly low IDC value - flagSkip = 1 << 6, ///< flag for defining a pad which is just ignored during the calculation of I1 and IDCDelta - flagFEC = 1 << 7, ///< flag for a whole masked FEC - flagNeighbour = 1 << 8, ///< flag if n neighbouring pads are outlier - flagAllNoneGood = flagDeadPad | flagUnknownPad | flagSaturatedPad | flagHighPad | flagLowPad | flagSkip | flagFEC | flagNeighbour, -}; - -inline PadFlags operator&(PadFlags a, PadFlags b) { return static_cast(static_cast(a) & static_cast(b)); } -inline PadFlags operator~(PadFlags a) { return static_cast(~static_cast(a)); } -inline PadFlags operator|(PadFlags a, PadFlags b) { return static_cast(static_cast(a) | static_cast(b)); } - // default point definitions for PointND, PointNDlocal, PointNDglobal are in // MathUtils/CartesianND.h diff --git a/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h b/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h index f463e9011c935..fd5abca99cb0f 100644 --- a/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h +++ b/DataFormats/Detectors/TPC/src/DataFormatsTPCLinkDef.h @@ -22,7 +22,6 @@ #pragma link C++ class o2::tpc::ClusterHardwareContainerFixedSize < 8192> + ; #pragma link C++ class o2::tpc::ClusterNativeContainer + ; #pragma link C++ class o2::tpc::Digit + ; -#pragma link C++ enum o2::tpc::PadFlags + ; // enum itself #pragma link C++ class o2::tpc::ZeroSuppressedContainer8kb + ; #pragma link C++ class std::vector < o2::tpc::ClusterNative> + ; #pragma link C++ class std::vector < o2::tpc::ClusterNativeContainer> + ; @@ -30,7 +29,6 @@ #pragma link C++ class std::vector < o2::tpc::ClusterHardwareContainerFixedSize < 8192>> + ; #pragma link C++ class std::vector < o2::tpc::ClusterHardwareContainer8kb> + ; #pragma link C++ class std::vector < o2::tpc::Digit> + ; -#pragma link C++ class std::vector < o2::tpc::PadFlags> + ; #pragma link C++ class std::vector < o2::tpc::ZeroSuppressedContainer8kb> + ; #pragma link C++ class o2::tpc::TrackTPC + ; #pragma link C++ class o2::tpc::LaserTrack + ; diff --git a/Detectors/TPC/CMakeLists.txt b/Detectors/TPC/CMakeLists.txt index e3de1ca57c1be..aea0dee361874 100644 --- a/Detectors/TPC/CMakeLists.txt +++ b/Detectors/TPC/CMakeLists.txt @@ -10,6 +10,7 @@ # or submit itself to any jurisdiction. add_subdirectory(base) +add_subdirectory(baserecsim) add_subdirectory(reconstruction) add_subdirectory(calibration) add_subdirectory(simulation) diff --git a/Detectors/TPC/base/CMakeLists.txt b/Detectors/TPC/base/CMakeLists.txt index a82214d8c070f..6456207e50530 100644 --- a/Detectors/TPC/base/CMakeLists.txt +++ b/Detectors/TPC/base/CMakeLists.txt @@ -12,7 +12,6 @@ o2_add_library(TPCBase SOURCES src/CalArray.cxx src/CalDet.cxx - src/CDBInterface.cxx src/ContainerFactory.cxx src/CRU.cxx src/DigitPos.cxx @@ -24,7 +23,6 @@ o2_add_library(TPCBase src/PadRegionInfo.cxx src/PadROCPos.cxx src/PadSecPos.cxx - src/Painter.cxx src/ParameterDetector.cxx src/ParameterElectronics.cxx src/ParameterGas.cxx @@ -37,16 +35,13 @@ o2_add_library(TPCBase src/CRUCalibHelpers.cxx src/IonTailSettings.cxx src/FEEConfig.cxx - src/DeadChannelMapCreator.cxx src/CommonModeCorrection.cxx PUBLIC_LINK_LIBRARIES Vc::Vc Boost::boost O2::DataFormatsTPC O2::DetectorsRaw O2::CCDB FairRoot::Base) o2_target_root_dictionary(TPCBase - EXTRA_PATCH src/TPCFlagsMemberCustomStreamer.cxx HEADERS include/TPCBase/CalArray.h include/TPCBase/CalDet.h - include/TPCBase/CDBInterface.h include/TPCBase/ContainerFactory.h include/TPCBase/CRU.h include/TPCBase/DigitPos.h @@ -58,7 +53,6 @@ o2_target_root_dictionary(TPCBase include/TPCBase/PadRegionInfo.h include/TPCBase/PadROCPos.h include/TPCBase/PadSecPos.h - include/TPCBase/Painter.h include/TPCBase/ParameterDetector.h include/TPCBase/ParameterElectronics.h include/TPCBase/ParameterGas.h @@ -71,26 +65,13 @@ o2_target_root_dictionary(TPCBase include/TPCBase/CRUCalibHelpers.h include/TPCBase/IonTailSettings.h include/TPCBase/FEEConfig.h - include/TPCBase/DeadChannelMapCreator.h - include/TPCBase/CommonModeCorrection.h - include/TPCBase/CDBTypes.h) + include/TPCBase/CommonModeCorrection.h) o2_add_test(Base COMPONENT_NAME tpc PUBLIC_LINK_LIBRARIES O2::TPCBase SOURCES test/testTPCBase.cxx LABELS tpc) -if(BUILD_SIMULATION) - # this test needs CCDB/XROOTD which is for sure - # available in the default-o2 software stack - o2_add_test(CalDet - COMPONENT_NAME tpc - PUBLIC_LINK_LIBRARIES O2::TPCBase - SOURCES test/testTPCCalDet.cxx - ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage - LABELS tpc) -endif() - o2_add_test(Mapper COMPONENT_NAME tpc PUBLIC_LINK_LIBRARIES O2::TPCBase diff --git a/Detectors/TPC/base/src/TPCBaseLinkDef.h b/Detectors/TPC/base/src/TPCBaseLinkDef.h index 4fdde1ca55518..2b7a7ff19542d 100644 --- a/Detectors/TPC/base/src/TPCBaseLinkDef.h +++ b/Detectors/TPC/base/src/TPCBaseLinkDef.h @@ -21,20 +21,15 @@ #pragma link C++ class o2::tpc::CalArray < unsigned> + ; #pragma link C++ class o2::tpc::CalArray < short> + ; #pragma link C++ class o2::tpc::CalArray < bool> + ; -#pragma link C++ class o2::tpc::CalArray < o2::tpc::PadFlags> + ; #pragma link C++ class o2::tpc::CalDet < float> + ; #pragma link C++ class o2::tpc::CalDet < double> + ; #pragma link C++ class o2::tpc::CalDet < int> + ; #pragma link C++ class o2::tpc::CalDet < unsigned> + ; #pragma link C++ class o2::tpc::CalDet < short> + ; #pragma link C++ class o2::tpc::CalDet < bool> + ; -#pragma link C++ class o2::tpc::CalDet < o2::tpc::PadFlags> + ; #pragma link C++ class std::vector < o2::tpc::CalDet < float>> + ; #pragma link C++ class std::vector < o2::tpc::CalDet < float>*> + ; #pragma link C++ class std::unordered_map < std::string, o2::tpc::CalDet < float>> + ; -#pragma link C++ enum o2::tpc::CDBType; -#pragma link C++ class o2::tpc::CDBInterface; -#pragma link C++ class o2::tpc::CDBStorage; #pragma link C++ class o2::tpc::ContainerFactory; #pragma link C++ class o2::tpc::CRU; #pragma link C++ class o2::tpc::DigitPos; @@ -50,8 +45,6 @@ #pragma link C++ class o2::tpc::ROC; #pragma link C++ class o2::tpc::Sector; -#pragma link C++ class o2::tpc::painter + ; - // #pragma link C++ class std::vector + ; #pragma link C++ class o2::tpc::ParameterDetector; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::tpc::ParameterDetector> + ; @@ -90,5 +83,4 @@ #pragma link C++ function o2::tpc::cru_calib_helpers::getCalPad < 2>(const std::string_view, const std::string_view, std::string_view) #pragma link C++ function o2::tpc::cru_calib_helpers::getCalPad < 6>(const std::string_view, const std::string_view, std::string_view) -#pragma link C++ class o2::tpc::DeadChannelMapCreator + ; #endif diff --git a/Detectors/TPC/base/test/testTPCCDBInterface.cxx b/Detectors/TPC/base/test/testTPCCDBInterface.cxx index 5a5384a4134ed..a0f4142b3f807 100644 --- a/Detectors/TPC/base/test/testTPCCDBInterface.cxx +++ b/Detectors/TPC/base/test/testTPCCDBInterface.cxx @@ -21,7 +21,7 @@ #include "TFile.h" // o2 includes -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCBase/CalArray.h" #include "TPCBase/CalDet.h" #include "TPCBase/Mapper.h" diff --git a/Detectors/TPC/baserecsim/CMakeLists.txt b/Detectors/TPC/baserecsim/CMakeLists.txt new file mode 100644 index 0000000000000..b6c0f2644aa81 --- /dev/null +++ b/Detectors/TPC/baserecsim/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright 2019-2025 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(TPCBaseRecSim + SOURCES src/DeadChannelMapCreator.cxx + src/Painter.cxx + src/CDBInterface.cxx + PUBLIC_LINK_LIBRARIES O2::TPCBase) + +o2_target_root_dictionary(TPCBaseRecSim + EXTRA_PATCH src/TPCFlagsMemberCustomStreamer.cxx + HEADERS include/TPCBaseRecSim/Painter.h + include/TPCBaseRecSim/PadFlags.h + include/TPCBaseRecSim/DeadChannelMapCreator.h + include/TPCBaseRecSim/CDBTypes.h + include/TPCBaseRecSim/CDBInterface.h) + +if(BUILD_SIMULATION) + # this test needs CCDB/XROOTD which is for sure + # available in the default-o2 software stack + o2_add_test(CalDet + COMPONENT_NAME tpc + PUBLIC_LINK_LIBRARIES O2::TPCBaseRecSim + SOURCES test/testTPCCalDet.cxx + ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage + LABELS tpc) +endif() diff --git a/Detectors/TPC/base/include/TPCBase/CDBInterface.h b/Detectors/TPC/baserecsim/include/TPCBaseRecSim/CDBInterface.h similarity index 99% rename from Detectors/TPC/base/include/TPCBase/CDBInterface.h rename to Detectors/TPC/baserecsim/include/TPCBaseRecSim/CDBInterface.h index 4c28744f0378a..5b2c8e6d48251 100644 --- a/Detectors/TPC/base/include/TPCBase/CDBInterface.h +++ b/Detectors/TPC/baserecsim/include/TPCBaseRecSim/CDBInterface.h @@ -25,8 +25,8 @@ #include "CCDB/CcdbApi.h" #include "TPCBase/CalDet.h" #include "TPCBase/FEEConfig.h" -#include "TPCBase/CDBTypes.h" -#include "TPCBase/DeadChannelMapCreator.h" +#include "TPCBaseRecSim/CDBTypes.h" +#include "TPCBaseRecSim/DeadChannelMapCreator.h" #include "DataFormatsTPC/LtrCalibData.h" #include "DataFormatsTPC/Defs.h" #include "CommonUtils/NameConf.h" diff --git a/Detectors/TPC/base/include/TPCBase/CDBTypes.h b/Detectors/TPC/baserecsim/include/TPCBaseRecSim/CDBTypes.h similarity index 100% rename from Detectors/TPC/base/include/TPCBase/CDBTypes.h rename to Detectors/TPC/baserecsim/include/TPCBaseRecSim/CDBTypes.h diff --git a/Detectors/TPC/base/include/TPCBase/DeadChannelMapCreator.h b/Detectors/TPC/baserecsim/include/TPCBaseRecSim/DeadChannelMapCreator.h similarity index 98% rename from Detectors/TPC/base/include/TPCBase/DeadChannelMapCreator.h rename to Detectors/TPC/baserecsim/include/TPCBaseRecSim/DeadChannelMapCreator.h index 9d4317380f4bc..5a3fc38aa208b 100644 --- a/Detectors/TPC/base/include/TPCBase/DeadChannelMapCreator.h +++ b/Detectors/TPC/baserecsim/include/TPCBaseRecSim/DeadChannelMapCreator.h @@ -21,8 +21,8 @@ #include "CCDB/CcdbApi.h" -#include "DataFormatsTPC/Defs.h" -#include "TPCBase/CDBTypes.h" +#include "TPCBaseRecSim/PadFlags.h" +#include "TPCBaseRecSim/CDBTypes.h" #include "TPCBase/CalDet.h" #include "TPCBase/FEEConfig.h" diff --git a/Detectors/TPC/baserecsim/include/TPCBaseRecSim/PadFlags.h b/Detectors/TPC/baserecsim/include/TPCBaseRecSim/PadFlags.h new file mode 100644 index 0000000000000..e13a24adf407e --- /dev/null +++ b/Detectors/TPC/baserecsim/include/TPCBaseRecSim/PadFlags.h @@ -0,0 +1,44 @@ +// Copyright 2019-2025 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 Defs.h +/// @author Jens Wiechula, Jens.Wiechula@ikf.uni-frankfurt.de +/// + +/// @brief Global TPC definitions and constants + +#ifndef AliceO2_TPC_PadFlags_H +#define AliceO2_TPC_PadFlags_H + +namespace o2::tpc +{ + +enum class PadFlags : unsigned short { + flagGoodPad = 1 << 0, ///< flag for a good pad binary 0001 + flagDeadPad = 1 << 1, ///< flag for a dead pad binary 0010 + flagUnknownPad = 1 << 2, ///< flag for unknown status binary 0100 + flagSaturatedPad = 1 << 3, ///< flag for saturated status binary 0100 + flagHighPad = 1 << 4, ///< flag for pad with extremly high IDC value + flagLowPad = 1 << 5, ///< flag for pad with extremly low IDC value + flagSkip = 1 << 6, ///< flag for defining a pad which is just ignored during the calculation of I1 and IDCDelta + flagFEC = 1 << 7, ///< flag for a whole masked FEC + flagNeighbour = 1 << 8, ///< flag if n neighbouring pads are outlier + flagAllNoneGood = flagDeadPad | flagUnknownPad | flagSaturatedPad | flagHighPad | flagLowPad | flagSkip | flagFEC | flagNeighbour, +}; + +inline PadFlags operator&(PadFlags a, PadFlags b) { return static_cast(static_cast(a) & static_cast(b)); } +inline PadFlags operator~(PadFlags a) { return static_cast(~static_cast(a)); } +inline PadFlags operator|(PadFlags a, PadFlags b) { return static_cast(static_cast(a) | static_cast(b)); } + +} // namespace o2::tpc + +#endif diff --git a/Detectors/TPC/base/include/TPCBase/Painter.h b/Detectors/TPC/baserecsim/include/TPCBaseRecSim/Painter.h similarity index 100% rename from Detectors/TPC/base/include/TPCBase/Painter.h rename to Detectors/TPC/baserecsim/include/TPCBaseRecSim/Painter.h diff --git a/Detectors/TPC/base/src/CDBInterface.cxx b/Detectors/TPC/baserecsim/src/CDBInterface.cxx similarity index 99% rename from Detectors/TPC/base/src/CDBInterface.cxx rename to Detectors/TPC/baserecsim/src/CDBInterface.cxx index 06f6a360670dc..2aaf9c58cbe2c 100644 --- a/Detectors/TPC/base/src/CDBInterface.cxx +++ b/Detectors/TPC/baserecsim/src/CDBInterface.cxx @@ -28,7 +28,7 @@ // o2 includes #include "DataFormatsTPC/CalibdEdxCorrection.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCBase/ParameterDetector.h" #include "TPCBase/ParameterElectronics.h" #include "TPCBase/ParameterGEM.h" diff --git a/Detectors/TPC/base/src/DeadChannelMapCreator.cxx b/Detectors/TPC/baserecsim/src/DeadChannelMapCreator.cxx similarity index 98% rename from Detectors/TPC/base/src/DeadChannelMapCreator.cxx rename to Detectors/TPC/baserecsim/src/DeadChannelMapCreator.cxx index 8c4e754fc5327..2d41e277b8583 100644 --- a/Detectors/TPC/base/src/DeadChannelMapCreator.cxx +++ b/Detectors/TPC/baserecsim/src/DeadChannelMapCreator.cxx @@ -14,8 +14,8 @@ #include #include "CommonUtils/NameConf.h" #include "Framework/Logger.h" -#include "TPCBase/DeadChannelMapCreator.h" -#include "TPCBase/Painter.h" +#include "TPCBaseRecSim/DeadChannelMapCreator.h" +#include "TPCBaseRecSim/Painter.h" using namespace o2::tpc; diff --git a/Detectors/TPC/base/src/Painter.cxx b/Detectors/TPC/baserecsim/src/Painter.cxx similarity index 99% rename from Detectors/TPC/base/src/Painter.cxx rename to Detectors/TPC/baserecsim/src/Painter.cxx index ffbc149225212..a571b50607dd2 100644 --- a/Detectors/TPC/base/src/Painter.cxx +++ b/Detectors/TPC/baserecsim/src/Painter.cxx @@ -41,7 +41,8 @@ #include "TPCBase/Mapper.h" #include "TPCBase/CalDet.h" #include "TPCBase/CalArray.h" -#include "TPCBase/Painter.h" +#include "TPCBaseRecSim/Painter.h" +#include "TPCBaseRecSim/PadFlags.h" #include "TPCBase/Utils.h" #include "DataFormatsTPC/LaserTrack.h" diff --git a/Detectors/TPC/baserecsim/src/TPCBaseRecSimLinkDef.h b/Detectors/TPC/baserecsim/src/TPCBaseRecSimLinkDef.h new file mode 100644 index 0000000000000..37822e3c02669 --- /dev/null +++ b/Detectors/TPC/baserecsim/src/TPCBaseRecSimLinkDef.h @@ -0,0 +1,27 @@ +// Copyright 2019-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ enum o2::tpc::PadFlags + ; // enum itself +#pragma link C++ class std::vector < o2::tpc::PadFlags> + ; +#pragma link C++ enum o2::tpc::CDBType; +#pragma link C++ class o2::tpc::CDBInterface; +#pragma link C++ class o2::tpc::CDBStorage; +#pragma link C++ class o2::tpc::CalArray < o2::tpc::PadFlags> + ; +#pragma link C++ class o2::tpc::CalDet < o2::tpc::PadFlags> + ; +#pragma link C++ class o2::tpc::painter + ; +#pragma link C++ class o2::tpc::DeadChannelMapCreator + ; +#endif diff --git a/Detectors/TPC/base/src/TPCFlagsMemberCustomStreamer.cxx b/Detectors/TPC/baserecsim/src/TPCFlagsMemberCustomStreamer.cxx similarity index 100% rename from Detectors/TPC/base/src/TPCFlagsMemberCustomStreamer.cxx rename to Detectors/TPC/baserecsim/src/TPCFlagsMemberCustomStreamer.cxx diff --git a/Detectors/TPC/base/test/testTPCCalDet.cxx b/Detectors/TPC/baserecsim/test/testTPCCalDet.cxx similarity index 99% rename from Detectors/TPC/base/test/testTPCCalDet.cxx rename to Detectors/TPC/baserecsim/test/testTPCCalDet.cxx index fda38c2d03e91..bf4cfddb780f0 100644 --- a/Detectors/TPC/base/test/testTPCCalDet.cxx +++ b/Detectors/TPC/baserecsim/test/testTPCCalDet.cxx @@ -24,7 +24,7 @@ #include "TPCBase/CalDet.h" #include "TFile.h" #include "Framework/TypeTraits.h" -#include "TPCBase/DeadChannelMapCreator.h" +#include "TPCBaseRecSim/DeadChannelMapCreator.h" namespace o2::tpc { diff --git a/Detectors/TPC/calibration/CMakeLists.txt b/Detectors/TPC/calibration/CMakeLists.txt index e5cc25230d2fc..27f7f0200bb92 100644 --- a/Detectors/TPC/calibration/CMakeLists.txt +++ b/Detectors/TPC/calibration/CMakeLists.txt @@ -58,7 +58,7 @@ o2_add_library(TPCCalibration src/DigitAdd.cxx src/CorrectdEdxDistortions.cxx src/PressureTemperatureHelper.cxx - PUBLIC_LINK_LIBRARIES O2::DataFormatsTPC O2::TPCBase + PUBLIC_LINK_LIBRARIES O2::DataFormatsTPC O2::TPCBaseRecSim O2::TPCReconstruction ROOT::Minuit Microsoft.GSL::GSL O2::DetectorsCalibration @@ -118,16 +118,16 @@ o2_target_root_dictionary(TPCCalibration include/TPCCalibration/PressureTemperatureHelper.h) o2_add_test_root_macro(macro/comparePedestalsAndNoise.C - PUBLIC_LINK_LIBRARIES O2::TPCBase + PUBLIC_LINK_LIBRARIES O2::TPCBaseRecSim LABELS tpc) o2_add_test_root_macro(macro/drawNoiseAndPedestal.C - PUBLIC_LINK_LIBRARIES O2::TPCBase + PUBLIC_LINK_LIBRARIES O2::TPCBaseRecSim LABELS tpc) o2_add_test_root_macro(macro/drawPulser.C - PUBLIC_LINK_LIBRARIES O2::TPCBase + PUBLIC_LINK_LIBRARIES O2::TPCBaseRecSim LABELS tpc) o2_add_test_root_macro(macro/mergeNoiseAndPedestal.C - PUBLIC_LINK_LIBRARIES O2::TPCBase + PUBLIC_LINK_LIBRARIES O2::TPCBaseRecSim LABELS tpc) o2_add_test_root_macro(macro/runPedestal.C PUBLIC_LINK_LIBRARIES O2::TPCCalibration diff --git a/Detectors/TPC/calibration/include/TPCCalibration/IDCCCDBHelper.h b/Detectors/TPC/calibration/include/TPCCalibration/IDCCCDBHelper.h index 1b8ba21774f57..744201205de76 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/IDCCCDBHelper.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/IDCCCDBHelper.h @@ -17,6 +17,7 @@ #define ALICEO2_TPC_IDCCCDBHELPER_H_ #include #include "DataFormatsTPC/Defs.h" +#include "TPCBaseRecSim/PadFlags.h" #include "TPCBase/Sector.h" #include "Rtypes.h" diff --git a/Detectors/TPC/calibration/include/TPCCalibration/IDCFactorization.h b/Detectors/TPC/calibration/include/TPCCalibration/IDCFactorization.h index 1fe6486722d95..510b6c44d613b 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/IDCFactorization.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/IDCFactorization.h @@ -24,6 +24,7 @@ #include "TPCCalibration/IDCContainer.h" #include "TPCCalibration/IDCGroupHelperSector.h" #include "DataFormatsTPC/Defs.h" +#include "TPCBaseRecSim/PadFlags.h" #include namespace o2::tpc diff --git a/Detectors/TPC/calibration/macro/comparePedestalsAndNoise.C b/Detectors/TPC/calibration/macro/comparePedestalsAndNoise.C index 5f998453d9515..04ba2fdeafc27 100644 --- a/Detectors/TPC/calibration/macro/comparePedestalsAndNoise.C +++ b/Detectors/TPC/calibration/macro/comparePedestalsAndNoise.C @@ -12,11 +12,11 @@ #if !defined(__CLING__) || defined(__ROOTCLING__) #include "TROOT.h" #include "TFile.h" -#include "TPCBase/CalDet.h" +#include "TPCBaseRecSim/CalDet.h" #include "TH1F.h" #include "TH2F.h" #include "TCanvas.h" -#include "TPCBase/Painter.h" +#include "TPCBaseRecSim/Painter.h" #endif std::tuple getNoiseAndPedestalHistogram(const TString pedestalFile, int roc) diff --git a/Detectors/TPC/calibration/macro/drawNoiseAndPedestal.C b/Detectors/TPC/calibration/macro/drawNoiseAndPedestal.C index b4894ecf60eb9..45677ac7404ec 100644 --- a/Detectors/TPC/calibration/macro/drawNoiseAndPedestal.C +++ b/Detectors/TPC/calibration/macro/drawNoiseAndPedestal.C @@ -19,9 +19,9 @@ #include "TH2.h" #include "TFile.h" #include "TPCBase/CalDet.h" -#include "TPCBase/Painter.h" +#include "TPCBaseRecSim/Painter.h" #include "TPCBase/Utils.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPad.h" #include "TCanvas.h" #include "TH1F.h" diff --git a/Detectors/TPC/calibration/macro/drawPulser.C b/Detectors/TPC/calibration/macro/drawPulser.C index 97d14cfd95a58..3be3a958b0025 100644 --- a/Detectors/TPC/calibration/macro/drawPulser.C +++ b/Detectors/TPC/calibration/macro/drawPulser.C @@ -16,7 +16,7 @@ #include "TH2.h" #include "TFile.h" #include "TPCBase/CalDet.h" -#include "TPCBase/Painter.h" +#include "TPCBaseRecSim/Painter.h" #include "TPCBase/Utils.h" #include "TPCBase/Mapper.h" #include "TPad.h" diff --git a/Detectors/TPC/calibration/macro/prepareCMFiles.C b/Detectors/TPC/calibration/macro/prepareCMFiles.C index 08880ccbe4862..3bf18a9d14f8f 100644 --- a/Detectors/TPC/calibration/macro/prepareCMFiles.C +++ b/Detectors/TPC/calibration/macro/prepareCMFiles.C @@ -18,7 +18,7 @@ #include "TFile.h" #include "Framework/Logger.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCBase/Mapper.h" #include "TPCBase/CalDet.h" #include "TPCBase/Utils.h" diff --git a/Detectors/TPC/calibration/macro/prepareITFiles.C b/Detectors/TPC/calibration/macro/prepareITFiles.C index eac0355e0ddfd..215ddb7909c8d 100644 --- a/Detectors/TPC/calibration/macro/prepareITFiles.C +++ b/Detectors/TPC/calibration/macro/prepareITFiles.C @@ -21,7 +21,7 @@ #include "TFile.h" #include "Framework/Logger.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCBase/Mapper.h" #include "TPCBase/CalDet.h" #include "TPCBase/Utils.h" diff --git a/Detectors/TPC/calibration/macro/preparePedestalFiles.C b/Detectors/TPC/calibration/macro/preparePedestalFiles.C index 92bc1456e48d7..894827fffab1e 100644 --- a/Detectors/TPC/calibration/macro/preparePedestalFiles.C +++ b/Detectors/TPC/calibration/macro/preparePedestalFiles.C @@ -18,7 +18,7 @@ #include "TFile.h" #include "TROOT.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCBase/Mapper.h" #include "TPCBase/CalDet.h" #include "TPCBase/Utils.h" diff --git a/Detectors/TPC/calibration/src/CalculatedEdx.cxx b/Detectors/TPC/calibration/src/CalculatedEdx.cxx index 11f83f1c7189e..478acda1189c2 100644 --- a/Detectors/TPC/calibration/src/CalculatedEdx.cxx +++ b/Detectors/TPC/calibration/src/CalculatedEdx.cxx @@ -21,7 +21,7 @@ #include "DataFormatsTPC/ClusterNative.h" #include "DetectorsBase/Propagator.h" #include "CCDB/BasicCCDBManager.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCReconstruction/TPCFastTransformHelperO2.h" #include "CalibdEdxTrackTopologyPol.h" #include "DataFormatsParameters/GRPMagField.h" diff --git a/Detectors/TPC/calibration/src/CalibPadGainTracksBase.cxx b/Detectors/TPC/calibration/src/CalibPadGainTracksBase.cxx index 2d8c34810324b..8a2ad1df19200 100644 --- a/Detectors/TPC/calibration/src/CalibPadGainTracksBase.cxx +++ b/Detectors/TPC/calibration/src/CalibPadGainTracksBase.cxx @@ -15,7 +15,7 @@ #include "TPCCalibration/CalibPadGainTracksBase.h" #include "TPCCalibration/IDCDrawHelper.h" #include "TPCBase/ROC.h" -#include "TPCBase/Painter.h" +#include "TPCBaseRecSim/Painter.h" #include "TPCCalibration/CalibTreeDump.h" #include "TPCBase/Mapper.h" diff --git a/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx b/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx index e9d7474699ce2..038fe3c34e140 100644 --- a/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx +++ b/Detectors/TPC/calibration/src/CorrectionMapsLoader.cxx @@ -12,7 +12,7 @@ #include "TPCCalibration/CorrectionMapsLoader.h" #include "TPCCalibration/CorrMapParam.h" #include "TPCReconstruction/TPCFastTransformHelperO2.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "Framework/Logger.h" #include "Framework/ProcessingContext.h" #include "Framework/CCDBParamSpec.h" diff --git a/Detectors/TPC/calibration/src/IDCAverageGroup.cxx b/Detectors/TPC/calibration/src/IDCAverageGroup.cxx index f027a0a7d0056..63ab4d9e537ac 100644 --- a/Detectors/TPC/calibration/src/IDCAverageGroup.cxx +++ b/Detectors/TPC/calibration/src/IDCAverageGroup.cxx @@ -15,12 +15,13 @@ #include "TPCCalibration/IDCDrawHelper.h" #include "CommonUtils/TreeStreamRedirector.h" #include "TPCBase/Mapper.h" +#include "TPCBaseRecSim/PadFlags.h" #include "CommonConstants/MathConstants.h" // root includes #include "TFile.h" #include "TKey.h" -#include "TPCBase/Painter.h" +#include "TPCBaseRecSim/Painter.h" #include "TH2Poly.h" #include "TCanvas.h" #include "TLatex.h" diff --git a/Detectors/TPC/calibration/src/IDCCCDBHelper.cxx b/Detectors/TPC/calibration/src/IDCCCDBHelper.cxx index a9fb8f0c4675f..189d1035fc767 100644 --- a/Detectors/TPC/calibration/src/IDCCCDBHelper.cxx +++ b/Detectors/TPC/calibration/src/IDCCCDBHelper.cxx @@ -18,7 +18,7 @@ #include "TPCBase/CalDet.h" #include "TPCBase/Mapper.h" #include "CommonUtils/TreeStreamRedirector.h" -#include "TPCBase/Painter.h" +#include "TPCBaseRecSim/Painter.h" #include "TStyle.h" #include "TLine.h" diff --git a/Detectors/TPC/calibration/src/IDCDrawHelper.cxx b/Detectors/TPC/calibration/src/IDCDrawHelper.cxx index 3a0b11b4a3beb..a5181cc36706d 100644 --- a/Detectors/TPC/calibration/src/IDCDrawHelper.cxx +++ b/Detectors/TPC/calibration/src/IDCDrawHelper.cxx @@ -10,7 +10,7 @@ // or submit itself to any jurisdiction. #include "TPCCalibration/IDCDrawHelper.h" -#include "TPCBase/Painter.h" +#include "TPCBaseRecSim/Painter.h" #include "TPCBase/Mapper.h" #include "TH2Poly.h" #include "TCanvas.h" diff --git a/Detectors/TPC/calibration/src/PressureTemperatureHelper.cxx b/Detectors/TPC/calibration/src/PressureTemperatureHelper.cxx index 2de4ee2086426..4f22ef8e35a03 100644 --- a/Detectors/TPC/calibration/src/PressureTemperatureHelper.cxx +++ b/Detectors/TPC/calibration/src/PressureTemperatureHelper.cxx @@ -14,7 +14,7 @@ /// \author Matthias Kleiner #include "TPCCalibration/PressureTemperatureHelper.h" -#include "TPCBase/CDBTypes.h" +#include "TPCBaseRecSim/CDBTypes.h" #include "Framework/ProcessingContext.h" #include "DataFormatsTPC/DCS.h" #include "Framework/InputRecord.h" diff --git a/Detectors/TPC/calibration/src/SACDrawHelper.cxx b/Detectors/TPC/calibration/src/SACDrawHelper.cxx index 9779681b464b7..db5a1efee209e 100644 --- a/Detectors/TPC/calibration/src/SACDrawHelper.cxx +++ b/Detectors/TPC/calibration/src/SACDrawHelper.cxx @@ -10,7 +10,7 @@ // or submit itself to any jurisdiction. #include "TPCCalibration/SACDrawHelper.h" -#include "TPCBase/Painter.h" +#include "TPCBaseRecSim/Painter.h" #include "TH2Poly.h" #include "TCanvas.h" #include "TLatex.h" diff --git a/Detectors/TPC/calibration/src/VDriftHelper.cxx b/Detectors/TPC/calibration/src/VDriftHelper.cxx index 71c4e50a63fcf..dc8f46af06828 100644 --- a/Detectors/TPC/calibration/src/VDriftHelper.cxx +++ b/Detectors/TPC/calibration/src/VDriftHelper.cxx @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCCalibration/VDriftHelper.h" #include "DataFormatsTPC/LtrCalibData.h" #include "TPCBase/ParameterGas.h" diff --git a/Detectors/TPC/dcs/src/DCSConfigSpec.cxx b/Detectors/TPC/dcs/src/DCSConfigSpec.cxx index dc13d4ed83081..05ac93ea5e216 100644 --- a/Detectors/TPC/dcs/src/DCSConfigSpec.cxx +++ b/Detectors/TPC/dcs/src/DCSConfigSpec.cxx @@ -38,7 +38,7 @@ #include "CCDB/CcdbApi.h" #include "CommonUtils/NameConf.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCBase/CRUCalibHelpers.h" #include "TPCBase/FEEConfig.h" #include "TPCBase/FECInfo.h" diff --git a/Detectors/TPC/dcs/src/DCSSpec.cxx b/Detectors/TPC/dcs/src/DCSSpec.cxx index 1b64ff7a75ba4..ea4e3a29ff630 100644 --- a/Detectors/TPC/dcs/src/DCSSpec.cxx +++ b/Detectors/TPC/dcs/src/DCSSpec.cxx @@ -30,7 +30,7 @@ #include "DetectorsDCS/DeliveryType.h" #include "DetectorsDCS/AliasExpander.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCdcs/DCSProcessor.h" #include "TPCdcs/DCSSpec.h" diff --git a/Detectors/TPC/monitor/src/SimpleEventDisplayGUI.cxx b/Detectors/TPC/monitor/src/SimpleEventDisplayGUI.cxx index 8784f096e3202..5509aa7473fc8 100644 --- a/Detectors/TPC/monitor/src/SimpleEventDisplayGUI.cxx +++ b/Detectors/TPC/monitor/src/SimpleEventDisplayGUI.cxx @@ -45,7 +45,7 @@ #include "TPCBase/Mapper.h" #include "TPCBase/CalDet.h" #include "TPCBase/CalArray.h" -#include "TPCBase/Painter.h" +#include "TPCBaseRecSim/Painter.h" #include "DataFormatsTPC/Constants.h" #include "TPCMonitor/SimpleEventDisplayGUI.h" diff --git a/Detectors/TPC/qc/macro/runClusters.C b/Detectors/TPC/qc/macro/runClusters.C index ea1d1b54f429e..2fd4c919be321 100644 --- a/Detectors/TPC/qc/macro/runClusters.C +++ b/Detectors/TPC/qc/macro/runClusters.C @@ -18,7 +18,7 @@ #include "SimulationDataFormat/MCTruthContainer.h" #include "DataFormatsTPC/Constants.h" #include "TPCQC/Clusters.h" -#include "TPCBase/Painter.h" +#include "TPCBaseRecSim/Painter.h" #endif using namespace o2::tpc; diff --git a/Detectors/TPC/qc/macro/runPID.C b/Detectors/TPC/qc/macro/runPID.C index b015ac088334b..c693189a95652 100644 --- a/Detectors/TPC/qc/macro/runPID.C +++ b/Detectors/TPC/qc/macro/runPID.C @@ -25,7 +25,7 @@ #include "DataFormatsTPC/TrackTPC.h" #include "DataFormatsTPC/TrackCuts.h" #include "TPCBase/CalDet.h" -#include "TPCBase/Painter.h" +#include "TPCBaseRecSim/Painter.h" #include "TPCBase/Utils.h" #include "DataFormatsTPC/ClusterNative.h" #include "TPCQC/PID.h" diff --git a/Detectors/TPC/qc/src/Clusters.cxx b/Detectors/TPC/qc/src/Clusters.cxx index 4bf59ced195ed..dc728a10a6570 100644 --- a/Detectors/TPC/qc/src/Clusters.cxx +++ b/Detectors/TPC/qc/src/Clusters.cxx @@ -18,7 +18,7 @@ // o2 includes #include "TPCQC/Clusters.h" -#include "TPCBase/Painter.h" +#include "TPCBaseRecSim/Painter.h" #include "TPCBase/ROC.h" #include "TPCBase/CRU.h" #include "TPCBase/Mapper.h" diff --git a/Detectors/TPC/qc/src/IDCsVsSACs.cxx b/Detectors/TPC/qc/src/IDCsVsSACs.cxx index 55e93f580d8a4..604a1030c3d67 100644 --- a/Detectors/TPC/qc/src/IDCsVsSACs.cxx +++ b/Detectors/TPC/qc/src/IDCsVsSACs.cxx @@ -25,7 +25,7 @@ #include "TPCCalibration/SACFactorization.h" #include "TPCBase/CalDet.h" #include "TPCBase/Mapper.h" -#include "TPCBase/Painter.h" +#include "TPCBaseRecSim/Painter.h" TCanvas* o2::tpc::qc::IDCsVsSACs::drawComparisionSACandIDCZero(TCanvas* outputCanvas, int nbins1D, float xMin1D, float xMax1D, int nbins1DSAC, float xMin1DSAC, float xMax1DSAC) const { diff --git a/Detectors/TPC/simulation/macro/toyCluster.C b/Detectors/TPC/simulation/macro/toyCluster.C index d60e5a7c0f94e..7baeef1cb1a6b 100644 --- a/Detectors/TPC/simulation/macro/toyCluster.C +++ b/Detectors/TPC/simulation/macro/toyCluster.C @@ -44,7 +44,7 @@ #include "TPCBase/Mapper.h" #include "TPCBase/ParameterDetector.h" #include "TPCBase/ParameterElectronics.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCSimulation/ElectronTransport.h" #include "TPCSimulation/SAMPAProcessing.h" #include "TPCSimulation/Point.h" diff --git a/Detectors/TPC/simulation/src/DigitContainer.cxx b/Detectors/TPC/simulation/src/DigitContainer.cxx index c2e7226706eb2..dfff4b91d6451 100644 --- a/Detectors/TPC/simulation/src/DigitContainer.cxx +++ b/Detectors/TPC/simulation/src/DigitContainer.cxx @@ -17,7 +17,7 @@ #include #include #include "TPCBase/Mapper.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCBase/ParameterElectronics.h" #include "TPCBase/IonTailSettings.h" #include "SimConfig/DigiParams.h" diff --git a/Detectors/TPC/simulation/src/Digitizer.cxx b/Detectors/TPC/simulation/src/Digitizer.cxx index cb865d9f7f752..49abc0a0b99af 100644 --- a/Detectors/TPC/simulation/src/Digitizer.cxx +++ b/Detectors/TPC/simulation/src/Digitizer.cxx @@ -24,7 +24,7 @@ #include "TPCSimulation/GEMAmplification.h" #include "TPCSimulation/Point.h" #include "TPCSimulation/SAMPAProcessing.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCSpaceCharge/SpaceCharge.h" #include "TPCBase/Mapper.h" #include "TPCCalibration/CorrMapParam.h" diff --git a/Detectors/TPC/simulation/src/ElectronTransport.cxx b/Detectors/TPC/simulation/src/ElectronTransport.cxx index f6b6f906ce862..f9e36aa642158 100644 --- a/Detectors/TPC/simulation/src/ElectronTransport.cxx +++ b/Detectors/TPC/simulation/src/ElectronTransport.cxx @@ -14,7 +14,7 @@ /// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de #include "TPCSimulation/ElectronTransport.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include diff --git a/Detectors/TPC/simulation/src/GEMAmplification.cxx b/Detectors/TPC/simulation/src/GEMAmplification.cxx index 2dc363bf151b4..8d47464e9ef53 100644 --- a/Detectors/TPC/simulation/src/GEMAmplification.cxx +++ b/Detectors/TPC/simulation/src/GEMAmplification.cxx @@ -17,7 +17,7 @@ #include #include "MathUtils/CachingTF1.h" #include -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include #include "Framework/Logger.h" #include diff --git a/Detectors/TPC/simulation/src/IDCSim.cxx b/Detectors/TPC/simulation/src/IDCSim.cxx index 45597393d8f2a..3958115d95f7c 100644 --- a/Detectors/TPC/simulation/src/IDCSim.cxx +++ b/Detectors/TPC/simulation/src/IDCSim.cxx @@ -16,7 +16,7 @@ #include "TPCBase/Mapper.h" #include #include "Framework/Logger.h" -#include "TPCBase/Painter.h" +#include "TPCBaseRecSim/Painter.h" #include "TH2Poly.h" #include "TCanvas.h" #include "TLatex.h" diff --git a/Detectors/TPC/simulation/src/SAMPAProcessing.cxx b/Detectors/TPC/simulation/src/SAMPAProcessing.cxx index 83f50832abfac..462008846fa04 100644 --- a/Detectors/TPC/simulation/src/SAMPAProcessing.cxx +++ b/Detectors/TPC/simulation/src/SAMPAProcessing.cxx @@ -14,7 +14,7 @@ /// \author Andi Mathis, TU München, andreas.mathis@ph.tum.de #include "TPCSimulation/SAMPAProcessing.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include #include diff --git a/Detectors/TPC/simulation/test/testTPCDigitContainer.cxx b/Detectors/TPC/simulation/test/testTPCDigitContainer.cxx index 72e4dfaf6a0b2..73fca084507e5 100644 --- a/Detectors/TPC/simulation/test/testTPCDigitContainer.cxx +++ b/Detectors/TPC/simulation/test/testTPCDigitContainer.cxx @@ -23,7 +23,7 @@ #include "DataFormatsTPC/Digit.h" #include "TPCSimulation/DigitContainer.h" #include "TPCSimulation/SAMPAProcessing.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" namespace o2 { diff --git a/Detectors/TPC/simulation/test/testTPCElectronTransport.cxx b/Detectors/TPC/simulation/test/testTPCElectronTransport.cxx index 12732a52d7fa7..e42e60d5edabb 100644 --- a/Detectors/TPC/simulation/test/testTPCElectronTransport.cxx +++ b/Detectors/TPC/simulation/test/testTPCElectronTransport.cxx @@ -20,7 +20,7 @@ #include "TPCSimulation/ElectronTransport.h" #include "TPCBase/ParameterGas.h" #include "TPCBase/ParameterDetector.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TH1D.h" #include "TF1.h" diff --git a/Detectors/TPC/simulation/test/testTPCGEMAmplification.cxx b/Detectors/TPC/simulation/test/testTPCGEMAmplification.cxx index 63c092deb59c2..8a3ce711b52ef 100644 --- a/Detectors/TPC/simulation/test/testTPCGEMAmplification.cxx +++ b/Detectors/TPC/simulation/test/testTPCGEMAmplification.cxx @@ -20,7 +20,7 @@ #include "TPCSimulation/GEMAmplification.h" #include "TPCBase/ParameterGas.h" #include "TPCBase/ParameterGEM.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TH1D.h" #include "TF1.h" diff --git a/Detectors/TPC/simulation/test/testTPCSAMPAProcessing.cxx b/Detectors/TPC/simulation/test/testTPCSAMPAProcessing.cxx index a89ea335d60b5..05ed4393ea65c 100644 --- a/Detectors/TPC/simulation/test/testTPCSAMPAProcessing.cxx +++ b/Detectors/TPC/simulation/test/testTPCSAMPAProcessing.cxx @@ -18,7 +18,7 @@ #define BOOST_TEST_DYN_LINK #include #include "TPCSimulation/SAMPAProcessing.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include #include diff --git a/Detectors/TPC/spacecharge/CMakeLists.txt b/Detectors/TPC/spacecharge/CMakeLists.txt index a2f4cdb51becb..390e6c99c9c7e 100644 --- a/Detectors/TPC/spacecharge/CMakeLists.txt +++ b/Detectors/TPC/spacecharge/CMakeLists.txt @@ -15,7 +15,7 @@ o2_add_library(TPCSpaceCharge src/PoissonSolver.cxx src/TriCubic.cxx src/DataContainer3D.cxx - PUBLIC_LINK_LIBRARIES O2::TPCBase + PUBLIC_LINK_LIBRARIES O2::TPCBaseRecSim O2::Field Vc::Vc ROOT::Core diff --git a/Detectors/TPC/spacecharge/macro/createSCHistosFromHits.C b/Detectors/TPC/spacecharge/macro/createSCHistosFromHits.C index f6232018f3c59..cf4e5b2719b22 100644 --- a/Detectors/TPC/spacecharge/macro/createSCHistosFromHits.C +++ b/Detectors/TPC/spacecharge/macro/createSCHistosFromHits.C @@ -112,7 +112,7 @@ g++ -o createSCHistosFromHits createSCHistosFromHits.C -I ~/alice/sw/osx_x86-64/ #include "TPCBase/ParameterDetector.h" #include "TPCBase/ParameterGEM.h" #include "TPCBase/ParameterElectronics.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCSimulation/ElectronTransport.h" #include "TPCSimulation/GEMAmplification.h" #include "TPCSimulation/SAMPAProcessing.h" diff --git a/Detectors/TPC/spacecharge/src/SpaceCharge.cxx b/Detectors/TPC/spacecharge/src/SpaceCharge.cxx index 07101bac15c23..9b6a572b46406 100644 --- a/Detectors/TPC/spacecharge/src/SpaceCharge.cxx +++ b/Detectors/TPC/spacecharge/src/SpaceCharge.cxx @@ -25,7 +25,7 @@ #include "Field/MagneticField.h" #include "CommonUtils/TreeStreamRedirector.h" #include "TPCBase/CalDet.h" -#include "TPCBase/Painter.h" +#include "TPCBaseRecSim/Painter.h" #include "MathUtils/Utils.h" #include "DataFormatsParameters/GRPMagField.h" #include "GPUDebugStreamer.h" diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/CalibratorPadGainTracksSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/CalibratorPadGainTracksSpec.h index f9d5501196eb7..3ccef73a4a8fc 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/CalibratorPadGainTracksSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/CalibratorPadGainTracksSpec.h @@ -22,7 +22,7 @@ #include "CommonUtils/NameConf.h" #include "Framework/Task.h" #include "Framework/ConfigParamRegistry.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCWorkflow/ProcessingHelpers.h" #include "DetectorsBase/GRPGeomHelper.h" #include "DetectorsCalibration/Utils.h" diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadGainTracksSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadGainTracksSpec.h index 2491e5f71a889..516ea128acfe7 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadGainTracksSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadGainTracksSpec.h @@ -25,7 +25,7 @@ #include "DataFormatsParameters/GRPObject.h" #include "TPCWorkflow/ProcessingHelpers.h" #include "Framework/CCDBParamSpec.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCCalibration/VDriftHelper.h" #include "TPCCalibration/CorrectionMapsLoader.h" #include "DetectorsBase/GRPGeomHelper.h" diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadRawSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadRawSpec.h index 19cbeb05f7007..7579e334ff267 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadRawSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadRawSpec.h @@ -34,7 +34,7 @@ #include "DetectorsBase/TFIDInfoHelper.h" #include "DataFormatsTPC/TPCSectorHeader.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCCalibration/CalibPedestal.h" #include "TPCCalibration/CalibPulser.h" #include "TPCReconstruction/RawReaderCRU.h" diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCFLPIDCSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCFLPIDCSpec.h index ec3e158590661..e4b85ad7c04d9 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/TPCFLPIDCSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCFLPIDCSpec.h @@ -31,7 +31,7 @@ #include "TPCCalibration/IDCFactorization.h" #include "Framework/CCDBParamSpec.h" #include "TPCWorkflow/ProcessingHelpers.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" using namespace o2::framework; using o2::header::gDataOriginTPC; diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCFactorizeIDCSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCFactorizeIDCSpec.h index 667386e6481ca..c8384cf9c9264 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/TPCFactorizeIDCSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCFactorizeIDCSpec.h @@ -35,7 +35,7 @@ #include "TPCBase/CRU.h" #include "CommonUtils/NameConf.h" #include "TPCWorkflow/ProcessingHelpers.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "DetectorsCalibration/Utils.h" #include "TPCCalibration/IDCCCDBHelper.h" diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCFactorizeSACSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCFactorizeSACSpec.h index f191f5f44761b..1757f3e223e86 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/TPCFactorizeSACSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCFactorizeSACSpec.h @@ -29,7 +29,7 @@ #include "CCDB/CcdbApi.h" #include "TPCWorkflow/TPCDistributeSACSpec.h" #include "TPCWorkflow/ProcessingHelpers.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "DetectorsCalibration/Utils.h" #include "Framework/InputRecordWalker.h" diff --git a/Detectors/TPC/workflow/src/CalDetMergerPublisherSpec.cxx b/Detectors/TPC/workflow/src/CalDetMergerPublisherSpec.cxx index a504ffa606b84..bb3c927e3df4d 100644 --- a/Detectors/TPC/workflow/src/CalDetMergerPublisherSpec.cxx +++ b/Detectors/TPC/workflow/src/CalDetMergerPublisherSpec.cxx @@ -36,7 +36,7 @@ #include "DetectorsCalibration/Utils.h" #include "CCDB/CcdbApi.h" #include "CCDB/CcdbObjectInfo.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCBase/CalDet.h" #include "TPCBase/CRUCalibHelpers.h" #include "TPCWorkflow/CalibRawPartInfo.h" diff --git a/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx b/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx index e3943f92235ab..7c2e2db8188e8 100644 --- a/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx +++ b/Detectors/TPC/workflow/src/CalibdEdxSpec.cxx @@ -29,7 +29,7 @@ #include "GPUO2ConfigurableParam.h" #include "TPCCalibration/CalibdEdx.h" #include "TPCWorkflow/ProcessingHelpers.h" -#include "TPCBase/CDBTypes.h" +#include "TPCBaseRecSim/CDBTypes.h" #include "TPCBase/Utils.h" #include "DetectorsBase/GRPGeomHelper.h" diff --git a/Detectors/TPC/workflow/src/CalibratordEdxSpec.cxx b/Detectors/TPC/workflow/src/CalibratordEdxSpec.cxx index 82e6d5075d7f0..87e339f0643f4 100644 --- a/Detectors/TPC/workflow/src/CalibratordEdxSpec.cxx +++ b/Detectors/TPC/workflow/src/CalibratordEdxSpec.cxx @@ -33,7 +33,7 @@ #include "TPCCalibration/CalibratordEdx.h" #include "TPCWorkflow/ProcessingHelpers.h" #include "DetectorsBase/GRPGeomHelper.h" -#include "TPCBase/CDBTypes.h" +#include "TPCBaseRecSim/CDBTypes.h" #include "TPCBase/Utils.h" using namespace o2::framework; diff --git a/Detectors/TPC/workflow/src/SACProcessorSpec.cxx b/Detectors/TPC/workflow/src/SACProcessorSpec.cxx index e69533a0bb6d3..1d09b9f0a4fbe 100644 --- a/Detectors/TPC/workflow/src/SACProcessorSpec.cxx +++ b/Detectors/TPC/workflow/src/SACProcessorSpec.cxx @@ -25,7 +25,7 @@ #include "CommonUtils/TreeStreamRedirector.h" #include "DetectorsBase/GRPGeomHelper.h" #include "Framework/CCDBParamSpec.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "DataFormatsTPC/RawDataTypes.h" #include "TPCBase/RDHUtils.h" diff --git a/Detectors/TPC/workflow/src/TPCMergeIntegrateClusterSpec.cxx b/Detectors/TPC/workflow/src/TPCMergeIntegrateClusterSpec.cxx index 01538aab5ad90..2fdf0d001f475 100644 --- a/Detectors/TPC/workflow/src/TPCMergeIntegrateClusterSpec.cxx +++ b/Detectors/TPC/workflow/src/TPCMergeIntegrateClusterSpec.cxx @@ -25,7 +25,7 @@ #include "DetectorsCommonDataFormats/FileMetaData.h" #include "Framework/DataTakingContext.h" #include "TPCCalibration/IDCFactorization.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCBase/CalDet.h" #include diff --git a/Detectors/TPC/workflow/src/TPCScalerSpec.cxx b/Detectors/TPC/workflow/src/TPCScalerSpec.cxx index 6065079c05e96..f185b5e08c7e7 100644 --- a/Detectors/TPC/workflow/src/TPCScalerSpec.cxx +++ b/Detectors/TPC/workflow/src/TPCScalerSpec.cxx @@ -19,7 +19,7 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/CCDBParamSpec.h" #include "Framework/ConfigParamRegistry.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "DetectorsBase/GRPGeomHelper.h" #include "TPCCalibration/TPCScaler.h" #include "TPCCalibration/TPCMShapeCorrection.h" diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 2d5a955a5e911..7b1db436dbf7e 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -61,11 +61,11 @@ #include "display/GPUDisplayInterface.h" #include "TPCBase/Sector.h" #include "TPCBase/Utils.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCCalibration/VDriftHelper.h" #include "CorrectionMapsHelper.h" #include "TPCCalibration/CorrectionMapsLoader.h" -#include "TPCBase/DeadChannelMapCreator.h" +#include "TPCBaseRecSim/DeadChannelMapCreator.h" #include "SimulationDataFormat/ConstMCTruthContainer.h" #include "SimulationDataFormat/MCCompLabel.h" #include "Algorithm/Parser.h" diff --git a/GPU/Workflow/src/GPUWorkflowTPC.cxx b/GPU/Workflow/src/GPUWorkflowTPC.cxx index 13a3c4b6162b8..2b2f81246fc04 100644 --- a/GPU/Workflow/src/GPUWorkflowTPC.cxx +++ b/GPU/Workflow/src/GPUWorkflowTPC.cxx @@ -56,12 +56,12 @@ #include "display/GPUDisplayInterface.h" #include "TPCBase/Sector.h" #include "TPCBase/Utils.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCCalibration/VDriftHelper.h" #include "CorrectionMapsHelper.h" #include "TPCCalibration/CorrectionMapsLoader.h" #include "TPCCalibration/IDCContainer.h" -#include "TPCBase/DeadChannelMapCreator.h" +#include "TPCBaseRecSim/DeadChannelMapCreator.h" #include "SimulationDataFormat/ConstMCTruthContainer.h" #include "SimulationDataFormat/MCCompLabel.h" #include "Algorithm/Parser.h" diff --git a/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx b/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx index ea5c6ba272ec6..c45c746064101 100644 --- a/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx +++ b/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx @@ -32,7 +32,7 @@ #include "TPCDigitizerSpec.h" #include "TPCSimWorkflow/TPCDigitRootWriterSpec.h" #include "TPCBase/Sector.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" // needed in order to init the **SHARED** polyadist file (to be done before the digitizers initialize) #include "TPCSimulation/GEMAmplification.h" diff --git a/Steer/DigitizerWorkflow/src/TPCDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/TPCDigitizerSpec.cxx index 381e1ecdd3e91..68476c3a92a6d 100644 --- a/Steer/DigitizerWorkflow/src/TPCDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/TPCDigitizerSpec.cxx @@ -33,7 +33,7 @@ #include "Framework/Task.h" #include "DataFormatsParameters/GRPObject.h" #include "DataFormatsTPC/TPCSectorHeader.h" -#include "TPCBase/CDBInterface.h" +#include "TPCBaseRecSim/CDBInterface.h" #include "TPCBase/ParameterGEM.h" #include "DataFormatsTPC/Digit.h" #include "TPCSimulation/Digitizer.h" From c21d7d7a7ec080bbf31523f910935b266405a3e2 Mon Sep 17 00:00:00 2001 From: Francesco Noferini Date: Mon, 12 Jan 2026 17:47:47 +0100 Subject: [PATCH 071/234] add TOF channel in TPC timeseries (#14945) --- Detectors/TPC/workflow/src/TPCTimeSeriesSpec.cxx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Detectors/TPC/workflow/src/TPCTimeSeriesSpec.cxx b/Detectors/TPC/workflow/src/TPCTimeSeriesSpec.cxx index 5007019d52910..ee3acc808ccb7 100644 --- a/Detectors/TPC/workflow/src/TPCTimeSeriesSpec.cxx +++ b/Detectors/TPC/workflow/src/TPCTimeSeriesSpec.cxx @@ -210,14 +210,14 @@ class TPCTimeSeries : public Task indicesITSTPC[tracksITSTPC[i].getRefTPC().getIndex()] = {i, idxVtx}; } - std::vector> idxTPCTrackToTOFCluster; // store for each tpc track index the index to the TOF cluster + std::vector> idxTPCTrackToTOFCluster; // store for each tpc track index the index to the TOF cluster // get matches to TOF in case skimmed data is produced if (mUnbinnedWriter) { // getLTIntegralOut(), ///< L,TOF integral calculated during the propagation // getSignal() mSignal = 0.0; ///< TOF time in ps o2::track::TrackLTIntegral defLT; - idxTPCTrackToTOFCluster = std::vector>(tracksTPC.size(), {-1, -999, -999, defLT, 0, 0, 0}); + idxTPCTrackToTOFCluster = std::vector>(tracksTPC.size(), {-1, -999, -999, defLT, 0, 0, 0, 0}); const std::vector> tofMatches{recoData.getTPCTOFMatches(), recoData.getTPCTRDTOFMatches(), recoData.getITSTPCTOFMatches(), recoData.getITSTPCTRDTOFMatches()}; const auto& ft0rec = recoData.getFT0RecPoints(); @@ -289,7 +289,7 @@ class TPCTimeSeries : public Task mask |= o2::dataformats::MatchInfoTOF::QualityFlags::hasT0_1BCbefore; } - idxTPCTrackToTOFCluster[refTPC] = {tpctofmatch.getIdxTOFCl(), tpctofmatch.getDXatTOF(), tpctofmatch.getDZatTOF(), ltIntegral, signal, deltaT, mask}; + idxTPCTrackToTOFCluster[refTPC] = {tpctofmatch.getIdxTOFCl(), tpctofmatch.getDXatTOF(), tpctofmatch.getDZatTOF(), ltIntegral, signal, deltaT, mask, tpctofmatch.getChannel() % 8736}; } } } @@ -1122,7 +1122,7 @@ class TPCTimeSeries : public Task return isGoodTrack; } - void fillDCA(const gsl::span tracksTPC, const gsl::span tracksITSTPC, const gsl::span vertices, const int iTrk, const int iThread, const std::unordered_map>& indicesITSTPC, const gsl::span tracksITS, const std::vector>& idxTPCTrackToTOFCluster, const gsl::span tofClusters) + void fillDCA(const gsl::span tracksTPC, const gsl::span tracksITSTPC, const gsl::span vertices, const int iTrk, const int iThread, const std::unordered_map>& indicesITSTPC, const gsl::span tracksITS, const std::vector>& idxTPCTrackToTOFCluster, const gsl::span tofClusters) { const auto& trackFull = tracksTPC[iTrk]; const bool isGoodTrack = checkTrack(trackFull); @@ -1512,6 +1512,7 @@ class TPCTimeSeries : public Task << "vertexTime=" << vertexTime /// time stamp assigned to the vertex << "trackTime0=" << trackTime0 /// time stamp assigned to the track << "TOFmask=" << std::get<6>(idxTPCTrackToTOFCluster[iTrk]) /// delta T- TPC TOF + << "TOFchannel=" << std::get<7>(idxTPCTrackToTOFCluster[iTrk]) /// TOF channel inside a sector // TPC delta param << "deltaTPCParamInOutTgl=" << deltaTPCParamInOutTgl << "deltaTPCParamInOutQPt=" << deltaTPCParamInOutQPt From ddcdd1f32cf09b7d153a90183eca358a1549eb0f Mon Sep 17 00:00:00 2001 From: shahoian Date: Tue, 16 Dec 2025 11:34:09 +0100 Subject: [PATCH 072/234] reduce verbosity of ITS/MFT digitizer --- Detectors/ITSMFT/common/simulation/src/Digitizer.cxx | 10 +++++----- .../Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx | 12 ++++++------ Detectors/Upgrades/ITS3/simulation/src/Digitizer.cxx | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx b/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx index 53e0a2fcb096f..4a8af0cbe9737 100644 --- a/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx +++ b/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx @@ -108,10 +108,10 @@ void Digitizer::process(const std::vector* hits, int evID, int srcID) { // digitize single event, the time must have been set beforehand - LOG(info) << "Digitizing " << mGeometry->getName() << " hits of entry " << evID << " from source " - << srcID << " at time " << mEventTime << " ROFrame= " << mNewROFrame << ")" - << " cont.mode: " << isContinuous() - << " Min/Max ROFrames " << mROFrameMin << "/" << mROFrameMax; + LOG(debug) << "Digitizing " << mGeometry->getName() << " hits of entry " << evID << " from source " + << srcID << " at time " << mEventTime << " ROFrame= " << mNewROFrame << ")" + << " cont.mode: " << isContinuous() + << " Min/Max ROFrames " << mROFrameMin << "/" << mROFrameMax; // is there something to flush ? if (mNewROFrame > mROFrameMin) { @@ -164,7 +164,7 @@ void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt) mNewROFrame = nbc / mParams.getROFrameLengthInBC(); mIsBeforeFirstRO = false; } - LOG(info) << " NewROFrame " << mNewROFrame << " nbc " << nbc; + LOG(debug) << " NewROFrame " << mNewROFrame << " nbc " << nbc; // in continuous mode depends on starts of periodic readout frame mCollisionTimeWrtROF += (nbc % mParams.getROFrameLengthInBC()) * o2::constants::lhc::LHCBunchSpacingNS; diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx index 3ee952801f0c3..7c988faebf2df 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx @@ -103,11 +103,11 @@ void Digitizer::process(const std::vector* hits, int evID, int srcID) { // digitize single event, the time must have been set beforehand - LOG(info) << " Digitizing " << mGeometry->getName() << " (ID: " << mGeometry->getDetID() - << ") hits of entry " << evID << " from source " << srcID - << " at time " << mEventTime << " ROFrame= " << mNewROFrame << ")" - << " cont.mode: " << isContinuous() - << " Min/Max ROFrames " << mROFrameMin << "/" << mROFrameMax; + LOG(debug) << " Digitizing " << mGeometry->getName() << " (ID: " << mGeometry->getDetID() + << ") hits of entry " << evID << " from source " << srcID + << " at time " << mEventTime << " ROFrame= " << mNewROFrame << ")" + << " cont.mode: " << isContinuous() + << " Min/Max ROFrames " << mROFrameMin << "/" << mROFrameMax; std::cout << "Printing segmentation info: " << std::endl; SegmentationChip::Print(); @@ -159,7 +159,7 @@ void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt) mNewROFrame = nbc / mParams.getROFrameLengthInBC(); - LOG(info) << " NewROFrame " << mNewROFrame << " = " << nbc << "/" << mParams.getROFrameLengthInBC() << " (nbc/mParams.getROFrameLengthInBC()"; + LOG(debug) << " NewROFrame " << mNewROFrame << " = " << nbc << "/" << mParams.getROFrameLengthInBC() << " (nbc/mParams.getROFrameLengthInBC()"; // in continuous mode depends on starts of periodic readout frame mCollisionTimeWrtROF += (nbc % mParams.getROFrameLengthInBC()) * o2::constants::lhc::LHCBunchSpacingNS; diff --git a/Detectors/Upgrades/ITS3/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ITS3/simulation/src/Digitizer.cxx index 4560a656c1762..4b0374d925401 100644 --- a/Detectors/Upgrades/ITS3/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ITS3/simulation/src/Digitizer.cxx @@ -76,10 +76,10 @@ void Digitizer::process(const std::vector* hits, int evID, int srcI { // digitize single event, the time must have been set beforehand - LOG(info) << "Digitizing " << mGeometry->getName() << " hits of entry " << evID << " from source " - << srcID << " at time " << mEventTime << " ROFrame = " << mNewROFrame << ")" - << " cont.mode: " << isContinuous() - << " Min/Max ROFrames " << mROFrameMin << "/" << mROFrameMax; + LOG(debug) << "Digitizing " << mGeometry->getName() << " hits of entry " << evID << " from source " + << srcID << " at time " << mEventTime << " ROFrame = " << mNewROFrame << ")" + << " cont.mode: " << isContinuous() + << " Min/Max ROFrames " << mROFrameMin << "/" << mROFrameMax; // is there something to flush ? if (mNewROFrame > mROFrameMin) { From 1dc98c8718409275e68056f2d3fd21664804fffa Mon Sep 17 00:00:00 2001 From: Matthias Kleiner Date: Thu, 9 Jan 2025 15:27:48 +0100 Subject: [PATCH 073/234] TPC space-charge: Improve GEM frame charging-up distortions Adding: - downsampling of space-charge objects - simulation of n-sectors only - some helper functions - weighted filling of charging-up of GEM frames for smoother potential - set global distortions from function --- .../include/TPCSpaceCharge/DataContainer3D.h | 3 + .../TPCSpaceCharge/PoissonSolverHelpers.h | 3 +- .../include/TPCSpaceCharge/SpaceCharge.h | 58 +++-- .../TPC/spacecharge/src/DataContainer3D.cxx | 31 ++- .../TPC/spacecharge/src/PoissonSolver.cxx | 26 +- Detectors/TPC/spacecharge/src/SpaceCharge.cxx | 231 +++++++++++++----- 6 files changed, 259 insertions(+), 93 deletions(-) diff --git a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/DataContainer3D.h b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/DataContainer3D.h index 79400c3d3d214..73638c5b2982f 100644 --- a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/DataContainer3D.h +++ b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/DataContainer3D.h @@ -186,6 +186,9 @@ struct DataContainer3D { /// print the matrix void print() const; + /// convert a data container to a new datacontainer with different grid definition (e.g. different number of vertices) + DataContainer3D convert(const o2::tpc::RegularGrid3D& gridNew, const o2::tpc::RegularGrid3D& gridRef, const int threads = 1) const; + /// operator overload DataContainer3D& operator*=(const DataT value); DataContainer3D& operator+=(const DataContainer3D& other); diff --git a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/PoissonSolverHelpers.h b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/PoissonSolverHelpers.h index 218bddcf49402..933273d0b5eb9 100644 --- a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/PoissonSolverHelpers.h +++ b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/PoissonSolverHelpers.h @@ -19,6 +19,7 @@ #define ALICEO2_TPC_POISSONSOLVERHELPERS_H_ #include "CommonConstants/MathConstants.h" +#include "DataFormatsTPC/Defs.h" namespace o2 { @@ -55,7 +56,7 @@ struct MGParameters { ///< Parameter inline static int nMGCycle = 200; ///< number of multi grid cycle (V type) inline static int maxLoop = 7; ///< the number of tree-deep of multi grid inline static int gamma = 1; ///< number of iteration at coarsest level !TODO SET TO REASONABLE VALUE! - inline static bool normalizeGridToOneSector = false; ///< the grid in phi direction is squashed from 2 Pi to (2 Pi / SECTORSPERSIDE). This can used to get the potential for phi symmetric sc density or boundary potentials + inline static int normalizeGridToNSector = SECTORSPERSIDE; ///< the grid in phi direction is squashed from 2 Pi to (2 Pi / SECTORSPERSIDE). This can used to get the potential for phi symmetric sc density or boundary potentials }; template diff --git a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceCharge.h b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceCharge.h index ad76ec2b6da5b..d0c66d0ff3df1 100644 --- a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceCharge.h +++ b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceCharge.h @@ -204,10 +204,13 @@ class SpaceCharge /// simulate only one sector instead of 18 per side. This makes currently only sense for the static distortions (ToDo: simplify usage) /// phi max will be restricted to 2Pi/18 for this instance and for global instance of poisson solver - void setSimOneSector(); + void setSimOneSector() { setSimNSector(1); } + + /// simulate N sectors + void setSimNSector(const int nSectors); /// unsetting simulation of one sector - static void unsetSimOneSector(); + static void unsetSimNSector(); /// setting default potential (same potential for all GEM frames. The default value of 1000V are matched to distortions observed in laser data without X-Ray etc. /// \param side side of the TPC where the potential will be set @@ -308,10 +311,24 @@ class SpaceCharge /// scaling the space-charge density for given stack void scaleChargeDensityStack(const float scalingFactor, const Sector sector, const GEMstack stack); + /// scale the potential by a scaling factor + /// \param scalingFactor factor to scale the potential + /// \param side side for which the potential will be scaled + void scalePotential(const DataT scalingFactor, const Side side) { mPotential[side] *= scalingFactor; } + /// add space charge density from other object (this.mDensity = this.mDensity + other.mDensity) /// \param otherSC other space-charge object, which charge will be added to current object void addChargeDensity(const SpaceCharge& otherSC); + /// add global corrections from other space charge object + void addGlobalCorrections(const SpaceCharge& otherSC, const Side side); + + /// convert space-charge object to new definition of number of vertices + /// \param nZNew new number of vertices in z direction + /// \param nRNew new number of vertices in r direction + /// \param nPhiNew new number of vertices in phi direction + void downSampleObject(const int nZNew, const int nRNew, const int nPhiNew); + /// step 3: calculate the local distortions and corrections with an electric field /// \param type calculate local corrections or local distortions: type = o2::tpc::SpaceCharge<>::Type::Distortions or o2::tpc::SpaceCharge<>::Type::Corrections /// \param formulaStruct struct containing a method to evaluate the electric field Er, Ez, Ephi (analytical formula or by TriCubic interpolator) @@ -415,6 +432,9 @@ class SpaceCharge /// \param phi global phi coordinate DataT getDensityCyl(const DataT z, const DataT r, const DataT phi, const Side side) const; + /// get the potential for list of given coordinate + std::vector getDensityCyl(const std::vector& z, const std::vector& r, const std::vector& phi, const Side side) const; + /// get the potential for given coordinate /// \param z global z coordinate /// \param r global r coordinate @@ -1184,6 +1204,10 @@ class SpaceCharge /// \param gCorr function returning global corrections for given global coordinate void setGlobalCorrections(const std::function& gCorr, const Side side); + /// setting the global distortions directly from input function provided in global coordinates + /// \param gDist function returning global distortions for given global coordinate + void setGlobalDistortions(const std::function& gDist, const Side side); + /// set misalignment of ROC for shift in z /// \param sector sector for which the misalignment in z will be applied (if sector=-1 all sectors are shifted) /// \param type 0=IROC, 1=OROC, 2=IROC+OROC @@ -1229,7 +1253,16 @@ class SpaceCharge /// \param tgl tgl of the track /// \param nPoints number of points used to calculate the DCAr /// \param pcstream if provided debug output is being created - float getDCAr(float tgl, const int nPoints, const float phi, o2::utils::TreeStreamRedirector* pcstream = nullptr) const; + float getDCAr(float tgl, const int nPoints, const float phi, float rStart = -1, o2::utils::TreeStreamRedirector* pcstream = nullptr) const; + + /// \return returns nearest phi vertex for given phi position + size_t getNearestPhiVertex(const DataT phi, const Side side) const { return std::round(phi / getGridSpacingPhi(side)); } + + /// \return returns nearest r vertex for given radius position + size_t getNearestRVertex(const DataT r, const Side side) const { return std::round((r - getRMin(side)) / getGridSpacingR(side) + 0.5); } + + /// \return returns number of bins in phi direction for the gap between sectors and for the GEM frame + size_t getPhiBinsGapFrame(const Side side) const; private: ParamSpaceCharge mParamGrid{}; ///< parameters of the grid on which the calculations are performed @@ -1352,15 +1385,6 @@ class SpaceCharge /// dump the created electron tracks with calculateElectronDriftPath function to a tree void dumpElectronTracksToTree(const std::vector>, std::array>>& electronTracks, const int nSamplingPoints, const char* outFile) const; - /// \return returns nearest phi vertex for given phi position - size_t getNearestPhiVertex(const DataT phi, const Side side) const { return std::round(phi / getGridSpacingPhi(side)); } - - /// \return returns nearest r vertex for given radius position - size_t getNearestRVertex(const DataT r, const Side side) const { return std::round((r - getRMin(side)) / getGridSpacingR(side) + 0.5); } - - /// \return returns number of bins in phi direction for the gap between sectors and for the GEM frame - size_t getPhiBinsGapFrame(const Side side) const; - /// \return setting the boundary potential for given GEM stack void setPotentialBoundaryGEMFrameAlongPhi(const std::function& potentialFunc, const GEMstack stack, const bool bottom, const Side side, const bool outerFrame = false); @@ -1372,16 +1396,16 @@ class SpaceCharge void initAllBuffers(); - void setBoundaryFromIndices(const std::function& potentialFunc, const std::vector& indices, const Side side); + void setBoundaryFromIndices(const std::function& potentialFunc, const std::vector>& indices, const Side side); /// get indices of the GEM frame along r - std::vector getPotentialBoundaryGEMFrameAlongRIndices(const Side side) const; + std::vector> getPotentialBoundaryGEMFrameAlongRIndices(const Side side) const; /// get indices of the GEM frame along phi - std::vector getPotentialBoundaryGEMFrameAlongPhiIndices(const GEMstack stack, const bool bottom, const Side side, const bool outerFrame, const bool noGap = false) const; + std::vector> getPotentialBoundaryGEMFrameAlongPhiIndices(const GEMstack stack, const bool bottom, const Side side, const bool outerFrame, const bool noGap = false) const; void setROCMisalignment(int stackType, int misalignmentType, int sector, const float potMin, const float potMax); - void fillROCMisalignment(const std::vector& indicesTop, const std::vector& indicesBottom, int sector, int misalignmentType, const std::pair& deltaPotPar); + void fillROCMisalignment(const std::vector>& indicesTop, const std::vector>& indicesBottom, int sector, int misalignmentType, const std::pair& deltaPotPar); /// set potentialsdue to ROD misalignment void initRodAlignmentVoltages(const MisalignmentType misalignmentType, const FCType fcType, const int sector, const Side side, const float deltaPot); @@ -1389,6 +1413,8 @@ class SpaceCharge void calcGlobalDistCorrIterative(const DistCorrInterpolator& globCorr, const int maxIter, const DataT approachZ, const DataT approachR, const DataT approachPhi, const DataT diffCorr, const SpaceCharge* scSCale, float scale, const Type type); void calcGlobalDistCorrIterativeLinearCartesian(const DistCorrInterpolator& globCorr, const int maxIter, const DataT approachX, const DataT approachY, const DataT approachZ, const DataT diffCorr, const SpaceCharge* scSCale, float scale, const Type type); + void setGlobalDistCorr(const Type type, const std::function& gFunc, const Side side); + ClassDefNV(SpaceCharge, 6); }; diff --git a/Detectors/TPC/spacecharge/src/DataContainer3D.cxx b/Detectors/TPC/spacecharge/src/DataContainer3D.cxx index cd2802b975fd2..60d7c28b8c74e 100644 --- a/Detectors/TPC/spacecharge/src/DataContainer3D.cxx +++ b/Detectors/TPC/spacecharge/src/DataContainer3D.cxx @@ -331,7 +331,6 @@ void DataContainer3D::dumpSlice(std::string_view treename, std::string_vi ROOT::RDataFrame dFrame(treename, fileIn); auto df = dFrame.Define("slice", [rangeiZ, rangeiR, rangeiPhi](const std::pair>& values, unsigned short nz, unsigned short nr, unsigned short nphi) { - const bool simOneSectorOnly = MGParameters::normalizeGridToOneSector; std::vector ir; std::vector iphi; std::vector iz; @@ -370,12 +369,12 @@ void DataContainer3D::dumpSlice(std::string_view treename, std::string_vi const float rTmp = o2::tpc::GridProperties::getRMin() + o2::tpc::GridProperties::getGridSpacingR(nr) * iRTmp; const float zTmp = o2::tpc::GridProperties::getZMin() + o2::tpc::GridProperties::getGridSpacingZ(nz) * iZTmp; - const float phiTmp = o2::tpc::GridProperties::getPhiMin() + o2::tpc::GridProperties::getGridSpacingPhi(nphi) / (simOneSectorOnly ? SECTORSPERSIDE : 1) * iPhiTmp; + const float phiTmp = o2::tpc::GridProperties::getPhiMin() + o2::tpc::GridProperties::getGridSpacingPhi(nphi) * (MGParameters::normalizeGridToNSector / double(SECTORSPERSIDE)) * iPhiTmp; const float x = rTmp * std::cos(phiTmp); const float y = rTmp * std::sin(phiTmp); const LocalPosition3D pos(x, y, zTmp); - unsigned char secNum = simOneSectorOnly ? 0 : std::floor(phiTmp / SECPHIWIDTH); + unsigned char secNum = std::floor(phiTmp / SECPHIWIDTH); Sector sector(secNum + (pos.Z() < 0) * SECTORSPERSIDE); LocalPosition3D lPosTmp = Mapper::GlobalToLocal(pos, sector); @@ -428,10 +427,9 @@ void DataContainer3D::dumpInterpolation(std::string_view treename, std::s // define grid for interpolation using GridProp = GridProperties; - const RegularGrid3D mGrid3D(GridProp::ZMIN, GridProp::RMIN, GridProp::PHIMIN, GridProp::getGridSpacingZ(nz), GridProp::getGridSpacingR(nr), o2::tpc::GridProperties::getGridSpacingPhi(nphi) / (MGParameters::normalizeGridToOneSector ? SECTORSPERSIDE : 1), ParamSpaceCharge{nr, nz, nphi}); + const RegularGrid3D mGrid3D(GridProp::ZMIN, GridProp::RMIN, GridProp::PHIMIN, GridProp::getGridSpacingZ(nz), GridProp::getGridSpacingR(nr), o2::tpc::GridProperties::getGridSpacingPhi(nphi) * (MGParameters::normalizeGridToNSector / double(SECTORSPERSIDE)), ParamSpaceCharge{nr, nz, nphi}); auto interpolate = [&mGrid3D = std::as_const(mGrid3D), &data = std::as_const(data), rangeR, rangeZ, rangePhi, nR, nZ, nPhi](unsigned int, ULong64_t iPhi) { - const bool simOneSectorOnly = MGParameters::normalizeGridToOneSector; std::vector ir; std::vector iphi; std::vector iz; @@ -473,7 +471,7 @@ void DataContainer3D::dumpInterpolation(std::string_view treename, std::s const float x = rPos * std::cos(phiPos); const float y = rPos * std::sin(phiPos); const LocalPosition3D pos(x, y, zPos); - unsigned char secNum = simOneSectorOnly ? 0 : std::floor(phiPos / SECPHIWIDTH); + unsigned char secNum = std::floor(phiPos / SECPHIWIDTH); // TODO CHECK THIS Sector sector(secNum + (pos.Z() < 0) * SECTORSPERSIDE); LocalPosition3D lPosTmp = Mapper::GlobalToLocal(pos, sector); lPos.emplace_back(lPosTmp); @@ -512,6 +510,27 @@ bool DataContainer3D::getVertices(std::string_view treename, std::string_ return true; } +template +DataContainer3D DataContainer3D::convert(const o2::tpc::RegularGrid3D& gridNew, const o2::tpc::RegularGrid3D& gridRef, const int threads) const +{ + const int nZNew = gridNew.getNZ(); + const int nRNew = gridNew.getNR(); + const int nPhiNew = gridNew.getNPhi(); + DataContainer3D contCont(nZNew, nRNew, nPhiNew); +#pragma omp parallel for num_threads(threads) + for (size_t iPhi = 0; iPhi < nPhiNew; ++iPhi) { + const DataT phi = gridNew.getPhiVertex(iPhi); + for (size_t iR = 0; iR < nRNew; ++iR) { + const DataT radius = gridNew.getRVertex(iR); + for (size_t iZ = 0; iZ < nZNew; ++iZ) { + const DataT z = gridNew.getZVertex(iZ); + contCont(iZ, iR, iPhi) = interpolate(z, radius, phi, gridRef); + } + } + } + return contCont; +} + template class o2::tpc::DataContainer3D; template class o2::tpc::DataContainer3D; diff --git a/Detectors/TPC/spacecharge/src/PoissonSolver.cxx b/Detectors/TPC/spacecharge/src/PoissonSolver.cxx index 952f4b29111ce..d00e268f64125 100644 --- a/Detectors/TPC/spacecharge/src/PoissonSolver.cxx +++ b/Detectors/TPC/spacecharge/src/PoissonSolver.cxx @@ -940,7 +940,7 @@ void PoissonSolver::residue2D(Vector& residue, const Vector& matricesCurr for (int j = 1; j < tnZColumn - 1; ++j) { residue(i, j, iPhi) = ih2 * (coefficient1[i] * matricesCurrentV(i + 1, j, iPhi) + coefficient2[i] * matricesCurrentV(i - 1, j, iPhi) + tempRatio * (matricesCurrentV(i, j + 1, iPhi) + matricesCurrentV(i, j - 1, iPhi)) - inverseTempFourth * matricesCurrentV(i, j, iPhi)) + matricesCurrentCharge(i, j, iPhi); } // end cols - } // end nRRow + } // end nRRow // Boundary points. for (int i = 0; i < tnRRow; ++i) { @@ -997,7 +997,7 @@ void PoissonSolver::residue3D(Vector& residue, const Vector& matricesCurr coefficient3[i] * (signPlus * matricesCurrentV(i, j, mp1) + signMinus * matricesCurrentV(i, j, mm1)) - inverseCoefficient4[i] * matricesCurrentV(i, j, m)) + matricesCurrentCharge(i, j, m); } // end cols - } // end mParamGrid.NRVertices + } // end mParamGrid.NRVertices } } @@ -1263,9 +1263,9 @@ void PoissonSolver::relax3D(Vector& matricesCurrentV, const Vector& matri for (int i = isw; i < tnRRow - 1; i += 2) { (matricesCurrentV)(i, j, m) = (coefficient2[i] * (matricesCurrentV)(i - 1, j, m) + tempRatioZ * ((matricesCurrentV)(i, j - 1, m) + (matricesCurrentV)(i, j + 1, m)) + coefficient1[i] * (matricesCurrentV)(i + 1, j, m) + coefficient3[i] * (signPlus * (matricesCurrentV)(i, j, mp1) + signMinus * (matricesCurrentV)(i, j, mm1)) + (h2 * (matricesCurrentCharge)(i, j, m))) * coefficient4[i]; } // end cols - } // end mParamGrid.NRVertices - } // end phi - } // end sweep + } // end mParamGrid.NRVertices + } // end phi + } // end sweep } else if (MGParameters::relaxType == RelaxType::Jacobi) { // for each slice for (int m = 0; m < iPhi; ++m) { @@ -1306,8 +1306,8 @@ void PoissonSolver::relax3D(Vector& matricesCurrentV, const Vector& matri for (int i = 1; i < tnRRow - 1; ++i) { (matricesCurrentV)(i, j, m) = (coefficient2[i] * (matricesCurrentV)(i - 1, j, m) + tempRatioZ * ((matricesCurrentV)(i, j - 1, m) + (matricesCurrentV)(i, j + 1, m)) + coefficient1[i] * (matricesCurrentV)(i + 1, j, m) + coefficient3[i] * (signPlus * (matricesCurrentV)(i, j, mp1) + signMinus * (matricesCurrentV)(i, j, mm1)) + (h2 * (matricesCurrentCharge)(i, j, m))) * coefficient4[i]; } // end cols - } // end mParamGrid.NRVertices - } // end phi + } // end mParamGrid.NRVertices + } // end phi } else { // Case weighted Jacobi // TODO @@ -1329,15 +1329,15 @@ void PoissonSolver::relax2D(Vector& matricesCurrentV, const Vector& matri matricesCurrentV(i, j, iPhi) = tempFourth * (coefficient1[i] * matricesCurrentV(i + 1, j, iPhi) + coefficient2[i] * matricesCurrentV(i - 1, j, iPhi) + tempRatio * (matricesCurrentV(i, j + 1, iPhi) + matricesCurrentV(i, j - 1, iPhi)) + (h2 * matricesCurrentCharge(i, j, iPhi))); } // end cols - } // end mParamGrid.NRVertices - } // end pass red-black + } // end mParamGrid.NRVertices + } // end pass red-black } else if (MGParameters::relaxType == RelaxType::Jacobi) { for (int j = 1; j < tnZColumn - 1; ++j) { for (int i = 1; i < tnRRow - 1; ++i) { matricesCurrentV(i, j, iPhi) = tempFourth * (coefficient1[i] * matricesCurrentV(i + 1, j, iPhi) + coefficient2[i] * matricesCurrentV(i - 1, j, iPhi) + tempRatio * (matricesCurrentV(i, j + 1, iPhi) + matricesCurrentV(i, j - 1, iPhi)) + (h2 * matricesCurrentCharge(i, j, iPhi))); } // end cols - } // end mParamGrid.NRVertices + } // end mParamGrid.NRVertices } else if (MGParameters::relaxType == RelaxType::WeightedJacobi) { // Weighted Jacobi // TODO @@ -1421,7 +1421,7 @@ void PoissonSolver::restrict3D(Vector& matricesCurrentCharge, const Vecto matricesCurrentCharge(i, j, m) = residue(ii, jj, mm) / 8 + s1 / 16 + s2 / 32 + s3 / 64; } // end cols - } // end mParamGrid.NRVertices + } // end mParamGrid.NRVertices // for boundary for (int j = 0, jj = 0; j < tnZColumn; ++j, jj += 2) { @@ -1460,7 +1460,7 @@ void PoissonSolver::restrict2D(Vector& matricesCurrentCharge, const Vecto (residue(iip1, jjp1, iphi) + residue(iim1, jjp1, iphi) + residue(iip1, jjm1, iphi) + residue(iim1, jjm1, iphi)) / 16; } } // end cols - } // end mParamGrid.NRVertices + } // end mParamGrid.NRVertices // boundary // for boundary for (int j = 0, jj = 0; j < tnZColumn; ++j, jj += 2) { @@ -1520,7 +1520,7 @@ void PoissonSolver::calcCoefficients2D(unsigned int from, unsigned int to template DataT PoissonSolver::getGridSizePhiInv() { - return MGParameters::normalizeGridToOneSector ? (INVTWOPI * SECTORSPERSIDE) : INVTWOPI; + return INVTWOPI * SECTORSPERSIDE / MGParameters::normalizeGridToNSector; } template class o2::tpc::PoissonSolver; diff --git a/Detectors/TPC/spacecharge/src/SpaceCharge.cxx b/Detectors/TPC/spacecharge/src/SpaceCharge.cxx index 9b6a572b46406..b80d2a7606ee7 100644 --- a/Detectors/TPC/spacecharge/src/SpaceCharge.cxx +++ b/Detectors/TPC/spacecharge/src/SpaceCharge.cxx @@ -43,6 +43,7 @@ #include "TStopwatch.h" #include "ROOT/RDataFrame.hxx" #include "THnSparse.h" +#include "TRandom.h" #include @@ -246,6 +247,10 @@ void SpaceCharge::setDefaultStaticDistortionsGEMFrameChargeUp(const Side template size_t SpaceCharge::getPhiBinsGapFrame(const Side side) const { + if (MGParameters::normalizeGridToNSector == 1) { + return 0; + } + const auto& regInf = Mapper::instance().getPadRegionInfo(0); const float localYEdgeIROC = regInf.getPadsInRowRegion(0) / 2 * regInf.getPadWidth(); const auto globalPosGap = Mapper::LocalToGlobal(LocalPosition2D(regInf.getRadiusFirstRow(), -(localYEdgeIROC + GEMFrameParameters::WIDTHFRAME)), Sector(0)); @@ -268,16 +273,15 @@ void SpaceCharge::setPotentialBoundaryGEMFrameAlongR(const std::function< } template -std::vector SpaceCharge::getPotentialBoundaryGEMFrameAlongRIndices(const Side side) const +std::vector> SpaceCharge::getPotentialBoundaryGEMFrameAlongRIndices(const Side side) const { - const bool simOneSectorOnly = MGParameters::normalizeGridToOneSector; const auto radiusStart = std::sqrt(std::pow(GEMFrameParameters::LENGTHFRAMEIROCBOTTOM / 2, 2) + std::pow(GEMFrameParameters::POSBOTTOM[0], 2)); const auto rStart = getNearestRVertex(radiusStart, side); const auto radiusEnd = std::sqrt(std::pow(GEMFrameParameters::LENGTHFRAMEOROC3TOP / 2, 2) + std::pow(GEMFrameParameters::POSTOP[3], 2)); const auto rEnd = getNearestRVertex(radiusEnd, side); // mParamGrid.NRVertices - 1 - const int verticesPerSector = simOneSectorOnly ? mParamGrid.NPhiVertices : mParamGrid.NPhiVertices / SECTORSPERSIDE; + const int verticesPerSector = mParamGrid.NPhiVertices / MGParameters::normalizeGridToNSector; const auto& regInf = Mapper::instance().getPadRegionInfo(0); const float localYEdgeIROC = regInf.getPadsInRowRegion(0) / 2 * regInf.getPadWidth(); @@ -300,7 +304,8 @@ std::vector SpaceCharge::getPotentialBoundaryGEMFrameAlongRIndice radii.emplace_back(std::sqrt(std::pow(GEMFrameParameters::POSTOP[stack], 2) + std::pow(localYEdge, 2))); } - std::vector potentialInd; + std::vector> potentialInd; + const float weight = 1; for (size_t iR = rStart; iR < rEnd; ++iR) { const DataT radius = getRVertex(iR, side); auto const it = std::lower_bound(radii.begin(), radii.end(), radius); @@ -315,13 +320,13 @@ std::vector SpaceCharge::getPotentialBoundaryGEMFrameAlongRIndice break; } - for (int sector = 0; sector < (simOneSectorOnly ? 1 : SECTORSPERSIDE); ++sector) { + for (int sector = 0; sector < MGParameters::normalizeGridToNSector; ++sector) { const size_t iPhiLeft = sector * verticesPerSector + iPhiTmp; const size_t iZ = mParamGrid.NZVertices - 1; - potentialInd.emplace_back(mPotential[side].getDataIndex(iZ, iR, iPhiLeft)); + potentialInd.emplace_back(mPotential[side].getDataIndex(iZ, iR, iPhiLeft), weight); if (iPhiTmp > 0) { const size_t iPhiRight = (sector + 1) * verticesPerSector - iPhiTmp; - potentialInd.emplace_back(mPotential[side].getDataIndex(iZ, iR, iPhiRight)); + potentialInd.emplace_back(mPotential[side].getDataIndex(iZ, iR, iPhiRight), weight); } } } @@ -339,37 +344,35 @@ void SpaceCharge::setPotentialBoundaryGEMFrameAlongPhi(const std::functio } template -void SpaceCharge::setBoundaryFromIndices(const std::function& potentialFunc, const std::vector& indices, const Side side) +void SpaceCharge::setBoundaryFromIndices(const std::function& potentialFunc, const std::vector>& indices, const Side side) { - for (const auto& index : indices) { + /* + make check for the weights + Loop over bins in the radial direction + Check for duplicates and use the one with larger weight + */ + + for (const auto& indexw : indices) { + const int index = indexw.first; const int iZ = mPotential[side].getIndexZ(index); const int iR = mPotential[side].getIndexR(index); const int iPhi = mPotential[side].getIndexPhi(index); const DataT radius = getRVertex(iR, side); - mPotential[side](iZ, iR, iPhi) = potentialFunc(radius); + const float weight = indexw.second; + const float pot = mPotential[side](iZ, iR, iPhi); + const float potNew = weight * potentialFunc(radius); + if (std::abs(potNew) > std::abs(pot)) { + mPotential[side](iZ, iR, iPhi) = potNew; + } } } template -std::vector SpaceCharge::getPotentialBoundaryGEMFrameAlongPhiIndices(const GEMstack stack, const bool bottom, const Side side, const bool outerFrame, const bool noGap) const +std::vector> SpaceCharge::getPotentialBoundaryGEMFrameAlongPhiIndices(const GEMstack stack, const bool bottom, const Side side, const bool outerFrame, const bool noGap) const { - const bool simOneSectorOnly = MGParameters::normalizeGridToOneSector; - // to avoid double counting auto indices = getPotentialBoundaryGEMFrameAlongRIndices(side); - if (!bottom && outerFrame) { - // if OROC3 to OFC check outer GEM frame from OROC3! - const auto indicesOROC3 = getPotentialBoundaryGEMFrameAlongPhiIndices(GEMstack::OROC3gem, false, side, false); - indices.insert(indices.end(), indicesOROC3.begin(), indicesOROC3.end()); - std::sort(indices.begin(), indices.end()); - } else if (bottom && outerFrame) { - // if IROC to IFC check inner GEM frame from IROC - const auto indicesIROC = getPotentialBoundaryGEMFrameAlongPhiIndices(GEMstack::IROCgem, true, side, false); - indices.insert(indices.end(), indicesIROC.begin(), indicesIROC.end()); - std::sort(indices.begin(), indices.end()); - } - int region = 0; float offsStart = 0; float offsEnd = 0; @@ -415,10 +418,10 @@ std::vector SpaceCharge::getPotentialBoundaryGEMFrameAlongPhiIndi nVerticesR = 1; } - std::vector potentialInd; - const int verticesPerSector = simOneSectorOnly ? mParamGrid.NPhiVertices : mParamGrid.NPhiVertices / SECTORSPERSIDE; - const auto nBinsPhi = (outerFrame || noGap) ? 0 : (simOneSectorOnly ? 0 : getPhiBinsGapFrame(side)); - for (int sector = 0; sector < (simOneSectorOnly ? 1 : SECTORSPERSIDE); ++sector) { + std::vector> potentialInd; // index, weight + const int verticesPerSector = mParamGrid.NPhiVertices / MGParameters::normalizeGridToNSector; + const auto nBinsPhi = (outerFrame || noGap) ? 0 : getPhiBinsGapFrame(side); + for (int sector = 0; sector < MGParameters::normalizeGridToNSector; ++sector) { const auto offsetPhi = sector * verticesPerSector + verticesPerSector / 2; for (size_t iPhiLocal = 0; iPhiLocal <= (verticesPerSector / 2 - nBinsPhi); ++iPhiLocal) { const auto iPhiLeft = offsetPhi + iPhiLocal; @@ -432,31 +435,62 @@ std::vector SpaceCharge::getPotentialBoundaryGEMFrameAlongPhiIndi // end at gem frame if ((outerFrame && (stack == GEMstack::IROCgem))) { - nREnd = (radiusBottom - getRVertex(1, side)) / getGridSpacingR(side) + 2; // 2 safety margin + // TODO: remove this? + const float marginCM = 0; // 0.4; + const int nMargingBins = marginCM / getGridSpacingR(side) + 0.5; + nREnd = (radiusBottom - getRVertex(1, side) + 0.5) / getGridSpacingR(side) + nMargingBins; // 2 safety margin + radiusMax = 3 + getRVertex(getNearestRVertex(radiusBottom + getGridSpacingR(side) * nMargingBins, side), side); } - if (rStart == 0) { + rStart -= 1; + nREnd += 1; + if (rStart <= 0) { rStart = 1; } + if (nREnd >= mParamGrid.NRVertices) { + nREnd = mParamGrid.NRVertices - 1; + } + + float lxMin = radiusStart; + if ((outerFrame && (stack == GEMstack::IROCgem))) { + lxMin = 0; + } + const float lxMax = (nREnd == mParamGrid.NRVertices - 1) ? 9999 : radiusMax; for (size_t iR = rStart; iR < nREnd; ++iR) { const size_t iZ = mParamGrid.NZVertices - 1; + float weight = 1; if (iPhiLeft < getNPhiVertices()) { - if (noGap || !std::binary_search(indices.begin(), indices.end(), mPotential[side].getDataIndex(iZ, iR, iPhiLeft))) { - potentialInd.emplace_back(mPotential[side].getDataIndex(iZ, iR, iPhiLeft)); + if (noGap || !std::binary_search(indices.begin(), indices.end(), std::make_pair(mPotential[side].getDataIndex(iZ, iR, iPhiLeft), 0.0f), [](const auto& a, const auto& b) { return (a.first < b.first); })) { + + // check how much of the bin is in the lx range and assign weigth + const int nIterPoints = 1000; + int nPointsGood = 0; + for (int i = 0; i < nIterPoints; ++i) { + const float radius = getRVertex(iR, side) + getGridSpacingR(side) * gRandom->Uniform(-0.5, 0.5); + const float phi = getGridSpacingPhi(side) * gRandom->Uniform(-0.5, 0.5); + const DataT lx = radius * std::cos(phi + localphi); + if ((lx >= lxMin) && (lx <= lxMax)) { + ++nPointsGood; + } + } + weight = nPointsGood / double(nIterPoints); + potentialInd.emplace_back(mPotential[side].getDataIndex(iZ, iR, iPhiLeft), weight); } } - if (iPhiLocal && (noGap || !std::binary_search(indices.begin(), indices.end(), mPotential[side].getDataIndex(iZ, iR, iPhiRight)))) { - potentialInd.emplace_back(mPotential[side].getDataIndex(iZ, iR, iPhiRight)); + if (iPhiLocal && (noGap || !std::binary_search(indices.begin(), indices.end(), std::make_pair(mPotential[side].getDataIndex(iZ, iR, iPhiRight), 0.0f), [](const auto& a, const auto& b) { return (a.first < b.first); }))) { + potentialInd.emplace_back(mPotential[side].getDataIndex(iZ, iR, iPhiRight), weight); } } } } // remove duplicate entries - std::unordered_set set(potentialInd.begin(), potentialInd.end()); - potentialInd.assign(set.begin(), set.end()); std::sort(potentialInd.begin(), potentialInd.end()); + + // Remove duplicates + potentialInd.erase(std::unique(potentialInd.begin(), potentialInd.end()), potentialInd.end()); + return potentialInd; } @@ -1809,6 +1843,18 @@ DataT SpaceCharge::getDensityCyl(const DataT z, const DataT r, const Data return mInterpolatorDensity[side](z, r, phi); } +template +std::vector SpaceCharge::getDensityCyl(const std::vector& z, const std::vector& r, const std::vector& phi, const Side side) const +{ + const auto nPoints = z.size(); + std::vector density(nPoints); +#pragma omp parallel for num_threads(sNThreads) + for (size_t i = 0; i < nPoints; ++i) { + density[i] = getDensityCyl(z[i], r[i], phi[i], side); + } + return density; +} + template DataT SpaceCharge::getPotentialCyl(const DataT z, const DataT r, const DataT phi, const Side side) const { @@ -1885,7 +1931,8 @@ void SpaceCharge::getCorrections(const DataT x, const DataT y, const Data } else { // convert cartesian to polar const DataT radius = getRadiusFromCartesian(x, y); - const DataT phi = getPhiFromCartesian(x, y); + DataT phi = getPhiFromCartesian(x, y); + o2::math_utils::detail::bringTo02PiGen(phi); DataT corrR{}; DataT corrRPhi{}; @@ -2421,7 +2468,7 @@ void SpaceCharge::makeElectronDriftPathGif(const char* inpFile, TH2F& hDu template void SpaceCharge::dumpToTree(const char* outFileName, const Side side, const int nZPoints, const int nRPoints, const int nPhiPoints, const bool randomize) const { - const DataT phiSpacing = GridProp::getGridSpacingPhi(nPhiPoints) / (MGParameters::normalizeGridToOneSector ? SECTORSPERSIDE : 1); + const DataT phiSpacing = GridProp::getGridSpacingPhi(nPhiPoints) * (MGParameters::normalizeGridToNSector / double(SECTORSPERSIDE)); const DataT rSpacing = GridProp::getGridSpacingR(nRPoints); const DataT zSpacing = side == Side::A ? GridProp::getGridSpacingZ(nZPoints) : -GridProp::getGridSpacingZ(nZPoints); @@ -2459,6 +2506,7 @@ void SpaceCharge::dumpToTree(const char* outFileName, const Side side, co std::vector> lPosOut(nPhiPoints); std::vector> sectorOut(nPhiPoints); std::vector> globalIdxOut(nPhiPoints); + std::vector> isOnPadPlane(nPhiPoints); #pragma omp parallel for num_threads(sNThreads) for (int iPhi = 0; iPhi < nPhiPoints; ++iPhi) { @@ -2494,6 +2542,7 @@ void SpaceCharge::dumpToTree(const char* outFileName, const Side side, co lPosOut[iPhi].reserve(nPoints); sectorOut[iPhi].reserve(nPoints); globalIdxOut[iPhi].reserve(nPoints); + isOnPadPlane[iPhi].reserve(nPoints); std::mt19937 rng(std::random_device{}()); DataT phiPos = iPhi * phiSpacing; @@ -2603,6 +2652,12 @@ void SpaceCharge::dumpToTree(const char* outFileName, const Side side, co sectorOut[iPhi].emplace_back(sector); const size_t idx = (iZ + nZPoints * (iR + iPhi * nRPoints)); globalIdxOut[iPhi].emplace_back(idx); + + const float xDist = getXFromPolar(radiusDistorted, phiDistorted); + const float yDist = getYFromPolar(radiusDistorted, phiDistorted); + GlobalPosition3D posTmp(xDist, yDist, zPos); + const DigitPos digiPadPos = o2::tpc::Mapper::instance().findDigitPosFromGlobalPosition(posTmp); + isOnPadPlane[iPhi].emplace_back(digiPadPos.isValid()); } } } @@ -2645,6 +2700,7 @@ void SpaceCharge::dumpToTree(const char* outFileName, const Side side, co dfStore = dfStore.DefineSlotEntry("bZ", [&bZOut = bZOut](unsigned int, ULong64_t entry) { return bZOut[entry]; }); dfStore = dfStore.DefineSlotEntry("bPhi", [&bPhiOut = bPhiOut](unsigned int, ULong64_t entry) { return bPhiOut[entry]; }); dfStore = dfStore.DefineSlotEntry("globalIndex", [&globalIdxOut = globalIdxOut](unsigned int, ULong64_t entry) { return globalIdxOut[entry]; }); + dfStore = dfStore.DefineSlotEntry("isOnPadPlane", [&isOnPadPlane = isOnPadPlane](unsigned int, ULong64_t entry) { return isOnPadPlane[entry]; }); dfStore.Snapshot("tree", outFileName); timer.Print("u"); } @@ -3356,20 +3412,20 @@ void SpaceCharge::readMetaData(std::string_view file) } template -void SpaceCharge::setSimOneSector() +void SpaceCharge::setSimNSector(const int nSectors) { LOGP(warning, "Use this feature only if you know what you are doing!"); - o2::tpc::MGParameters::normalizeGridToOneSector = true; - RegularGrid gridTmp[FNSIDES]{{GridProp::ZMIN, GridProp::RMIN, GridProp::PHIMIN, getSign(Side::A) * GridProp::getGridSpacingZ(mParamGrid.NZVertices), GridProp::getGridSpacingR(mParamGrid.NRVertices), GridProp::getGridSpacingPhi(mParamGrid.NPhiVertices) / SECTORSPERSIDE, mParamGrid}, - {GridProp::ZMIN, GridProp::RMIN, GridProp::PHIMIN, getSign(Side::C) * GridProp::getGridSpacingZ(mParamGrid.NZVertices), GridProp::getGridSpacingR(mParamGrid.NRVertices), GridProp::getGridSpacingPhi(mParamGrid.NPhiVertices) / SECTORSPERSIDE, mParamGrid}}; + o2::tpc::MGParameters::normalizeGridToNSector = nSectors; + RegularGrid gridTmp[FNSIDES]{{GridProp::ZMIN, GridProp::RMIN, GridProp::PHIMIN, getSign(Side::A) * GridProp::getGridSpacingZ(mParamGrid.NZVertices), GridProp::getGridSpacingR(mParamGrid.NRVertices), GridProp::getGridSpacingPhi(mParamGrid.NPhiVertices) / SECTORSPERSIDE * nSectors, mParamGrid}, + {GridProp::ZMIN, GridProp::RMIN, GridProp::PHIMIN, getSign(Side::C) * GridProp::getGridSpacingZ(mParamGrid.NZVertices), GridProp::getGridSpacingR(mParamGrid.NRVertices), GridProp::getGridSpacingPhi(mParamGrid.NPhiVertices) / SECTORSPERSIDE * nSectors, mParamGrid}}; mGrid3D[0] = gridTmp[0]; mGrid3D[1] = gridTmp[1]; } template -void SpaceCharge::unsetSimOneSector() +void SpaceCharge::unsetSimNSector() { - o2::tpc::MGParameters::normalizeGridToOneSector = false; + o2::tpc::MGParameters::normalizeGridToNSector = SECTORSPERSIDE; } template @@ -3424,6 +3480,20 @@ void SpaceCharge::addChargeDensity(const SpaceCharge& otherSC) mDensity[Side::C] += otherSC.mDensity[Side::C]; } +template +void SpaceCharge::addGlobalCorrections(const SpaceCharge& otherSC, const Side side) +{ + const bool sameGrid = (getNPhiVertices() == otherSC.getNPhiVertices()) && (getNRVertices() == otherSC.getNRVertices()) && (getNZVertices() == otherSC.getNZVertices()); + if (!sameGrid) { + LOGP(warning, "Space charge objects have different grid definition"); + return; + } + + mGlobalCorrdR[side] += otherSC.mGlobalCorrdR[side]; + mGlobalCorrdZ[side] += otherSC.mGlobalCorrdZ[side]; + mGlobalCorrdRPhi[side] += otherSC.mGlobalCorrdRPhi[side]; +} + template void SpaceCharge::fillChargeDensityFromHisto(const char* file, const char* nameA, const char* nameC) { @@ -3739,9 +3809,27 @@ void SpaceCharge::setIFCChargeUpFallingPot(const float deltaPot, const fl template void SpaceCharge::setGlobalCorrections(const std::function& gCorr, const Side side) { - initContainer(mGlobalCorrdR[side], true); - initContainer(mGlobalCorrdZ[side], true); - initContainer(mGlobalCorrdRPhi[side], true); + setGlobalDistCorr(Type::Corrections, gCorr, side); +} + +template +void SpaceCharge::setGlobalDistortions(const std::function& gDist, const Side side) +{ + setGlobalDistCorr(Type::Distortions, gDist, side); +} + +template +void SpaceCharge::setGlobalDistCorr(const Type type, const std::function& gFunc, const Side side) +{ + if (type == Type::Distortions) { + initContainer(mGlobalDistdR[side], true); + initContainer(mGlobalDistdZ[side], true); + initContainer(mGlobalDistdRPhi[side], true); + } else { + initContainer(mGlobalCorrdR[side], true); + initContainer(mGlobalCorrdZ[side], true); + initContainer(mGlobalCorrdRPhi[side], true); + } #pragma omp parallel for num_threads(sNThreads) for (unsigned int iPhi = 0; iPhi < mParamGrid.NPhiVertices; ++iPhi) { @@ -3761,7 +3849,7 @@ void SpaceCharge::setGlobalCorrections(const std::function::setGlobalCorrections(const std::function::setROCMisalignment(int stackType, int misalignmentType, } template -void SpaceCharge::fillROCMisalignment(const std::vector& indicesTop, const std::vector& indicesBottom, int sector, int misalignmentType, const std::pair& deltaPotPar) +void SpaceCharge::fillROCMisalignment(const std::vector>& indicesTop, const std::vector>& indicesBottom, int sector, int misalignmentType, const std::pair& deltaPotPar) { - for (const auto& index : indicesTop) { + for (const auto& indexw : indicesTop) { + const int index = indexw.first; const int iZ = DataContainer3D::getIndexZ(index, getNZVertices(), getNRVertices(), getNPhiVertices()); const int iRStart = DataContainer3D::getIndexR(index, getNZVertices(), getNRVertices(), getNPhiVertices()); const int iPhi = DataContainer3D::getIndexPhi(index, getNZVertices(), getNRVertices(), getNPhiVertices()); @@ -3853,7 +3948,8 @@ void SpaceCharge::fillROCMisalignment(const std::vector& indicesT for (size_t iR = iRStart; iR > 0; --iR) { const size_t currInd = (iZ + getNZVertices() * (iR + iPhi * getNRVertices())); - const bool foundVertexBottom = std::binary_search(indicesBottom.begin(), indicesBottom.end(), currInd); + const bool foundVertexBottom = std::binary_search(indicesBottom.begin(), indicesBottom.end(), std::make_pair(currInd, 0.0f), [](const auto& a, const auto& b) { return (a.first < b.first); }); + if (foundVertexBottom) { break; } @@ -3982,7 +4078,7 @@ void SpaceCharge::initAfterReadingFromFile() } template -float SpaceCharge::getDCAr(float tgl, const int nPoints, const float phi, o2::utils::TreeStreamRedirector* pcstream) const +float SpaceCharge::getDCAr(float tgl, const int nPoints, const float phi, float rStart, o2::utils::TreeStreamRedirector* pcstream) const { const float rmin = getRMin(o2::tpc::Side::A); std::vector dRphi; @@ -3990,7 +4086,7 @@ float SpaceCharge::getDCAr(float tgl, const int nPoints, const float phi, dRphi.reserve(nPoints); r.reserve(nPoints); for (int i = 0; i < nPoints; ++i) { - float radius = rmin + i; + float radius = (rStart > 0) ? (rStart + i) : (rmin + i); float z = tgl * radius; DataT distZ = 0; DataT distR = 0; @@ -4030,6 +4126,7 @@ float SpaceCharge::getDCAr(float tgl, const int nPoints, const float phi, << "r=" << r << "dRphi=" << dRphi << "tgl=" << tgl + << "phi=" << phi << "dca=" << dca << "rInterpol=" << rInterpol << "dRPhiInterpol=" << dRPhiInterpol @@ -4047,6 +4144,26 @@ void SpaceCharge::setPotential(int iz, int ir, int iphi, Side side, float mPotential[side](iz, ir, iphi) = val; } +template +void SpaceCharge::downSampleObject(const int nZNew, const int nRNew, const int nPhiNew) +{ + o2::tpc::SpaceCharge scNew(getBField(), nZNew, nRNew, nPhiNew); + for (int iside = 0; iside < 2; ++iside) { + const o2::tpc::Side side = (iside == 0) ? o2::tpc::Side::A : o2::tpc::Side::C; + const std::vector> dataRef{mLocalDistdR[iside], mLocalDistdZ[iside], mLocalDistdRPhi[iside], mLocalVecDistdR[iside], mLocalVecDistdZ[iside], mLocalVecDistdRPhi[iside], mLocalCorrdR[iside], mLocalCorrdZ[iside], mLocalCorrdRPhi[iside], mGlobalDistdR[iside], mGlobalDistdZ[iside], mGlobalDistdRPhi[iside], mGlobalCorrdR[iside], mGlobalCorrdZ[iside], mGlobalCorrdRPhi[iside], mDensity[iside], mPotential[iside], mElectricFieldEr[iside], mElectricFieldEz[iside], mElectricFieldEphi[iside]}; + const std::vector> dataNew{scNew.mLocalDistdR[iside], scNew.mLocalDistdZ[iside], scNew.mLocalDistdRPhi[iside], scNew.mLocalVecDistdR[iside], scNew.mLocalVecDistdZ[iside], scNew.mLocalVecDistdRPhi[iside], scNew.mLocalCorrdR[iside], scNew.mLocalCorrdZ[iside], scNew.mLocalCorrdRPhi[iside], scNew.mGlobalDistdR[iside], scNew.mGlobalDistdZ[iside], scNew.mGlobalDistdRPhi[iside], scNew.mGlobalCorrdR[iside], scNew.mGlobalCorrdZ[iside], scNew.mGlobalCorrdRPhi[iside], scNew.mDensity[iside], scNew.mPotential[iside], scNew.mElectricFieldEr[iside], scNew.mElectricFieldEz[iside], scNew.mElectricFieldEphi[iside]}; + for (int i = 0; i < dataRef.size(); ++i) { + const auto& objRef = dataRef[i].get(); + if (objRef.getNDataPoints()) { + auto& objNew = dataNew[i].get(); + scNew.initContainer(objNew, true); + objNew = objRef.convert(scNew.mGrid3D[iside], mGrid3D[iside], sNThreads); + } + } + } + *this = std::move(scNew); +} + using DataTD = double; template class o2::tpc::SpaceCharge; From b20c426d6a7678fa1dbee6491344076d9de868b6 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Tue, 13 Jan 2026 13:28:50 +0100 Subject: [PATCH 074/234] use better criterion to add arrow support service --- Framework/Core/src/runDataProcessing.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Framework/Core/src/runDataProcessing.cxx b/Framework/Core/src/runDataProcessing.cxx index 14bdb2d8c72d9..166f26878c363 100644 --- a/Framework/Core/src/runDataProcessing.cxx +++ b/Framework/Core/src/runDataProcessing.cxx @@ -3010,8 +3010,8 @@ int doMain(int argc, char** argv, o2::framework::WorkflowSpec const& workflow, ServiceSpecs driverServices = ServiceSpecHelpers::filterDisabled(CommonDriverServices::defaultServices(), driverServicesOverride); // We insert the hash for the internal devices. WorkflowHelpers::injectServiceDevices(physicalWorkflow, configContext); - auto reader = std::find_if(physicalWorkflow.begin(), physicalWorkflow.end(), [](DataProcessorSpec& spec) { return spec.name == "internal-dpl-aod-reader"; }); - if (reader != physicalWorkflow.end()) { + auto& dec = configContext.services().get(); + if (!(dec.requestedAODs.empty() && dec.requestedDYNs.empty() && dec.requestedIDXs.empty() && dec.requestedTIMs.empty())) { driverServices.push_back(ArrowSupport::arrowBackendSpec()); } for (auto& service : driverServices) { From 494f76c08b567f7660edccd151a76426fcac4f98 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 14 Jan 2026 16:45:15 +0100 Subject: [PATCH 075/234] Fix code checker report --- Detectors/EMCAL/calib/include/EMCALCalib/CellRecalibrator.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/CellRecalibrator.h b/Detectors/EMCAL/calib/include/EMCALCalib/CellRecalibrator.h index 571b43d05ef08..ea8a0445bbe5e 100644 --- a/Detectors/EMCAL/calib/include/EMCALCalib/CellRecalibrator.h +++ b/Detectors/EMCAL/calib/include/EMCALCalib/CellRecalibrator.h @@ -62,7 +62,7 @@ class CellRecalibrator public: /// \class CellTypeException /// \brief Handling of invalid cell types in calibration - class CellTypeException : public std::exception + class CellTypeException final : public std::exception { public: /// \brief Constructor @@ -73,7 +73,7 @@ class CellRecalibrator /// \brief Get error message of the exception /// \return Error message - const char* what() const noexcept final + [[nodiscard]] char const* what() const noexcept final { return "Only possible to calibrate cells of type high gain or low gain"; } @@ -208,4 +208,4 @@ std::ostream& operator<<(std::ostream& in, const CellRecalibrator& calib); } // namespace o2 -#endif // !ALCEO2_EMCAL_CELLRECALIBRATOR_H \ No newline at end of file +#endif // !ALCEO2_EMCAL_CELLRECALIBRATOR_H From 36176ca5c73048c3d34fb3261edd4298dd436178 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:50:50 +0100 Subject: [PATCH 076/234] DPL: add test for routing messages --- Framework/Core/test/test_ForwardInputs.cxx | 74 ++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/Framework/Core/test/test_ForwardInputs.cxx b/Framework/Core/test/test_ForwardInputs.cxx index fe9f70d1daadb..7081d600080b1 100644 --- a/Framework/Core/test/test_ForwardInputs.cxx +++ b/Framework/Core/test/test_ForwardInputs.cxx @@ -616,6 +616,80 @@ TEST_CASE("ForwardInputsSplitPayload") CHECK(result[1].Size() == 3); } +TEST_CASE("ForwardInputsSplitPayloadNoMessageSet") +{ + o2::header::DataHeader dh; + dh.dataOrigin = "TST"; + dh.dataDescription = "A"; + dh.subSpecification = 0; + dh.splitPayloadIndex = 2; + dh.splitPayloadParts = 2; + + o2::header::DataHeader dh2; + dh2.dataOrigin = "TST"; + dh2.dataDescription = "B"; + dh2.subSpecification = 0; + dh2.splitPayloadIndex = 0; + dh2.splitPayloadParts = 1; + + o2::framework::DataProcessingHeader dph{0, 1}; + + std::vector channels{ + fair::mq::Channel("from_A_to_B"), + fair::mq::Channel("from_A_to_C"), + }; + + bool consume = true; + bool copyByDefault = true; + FairMQDeviceProxy proxy; + std::vector routes{ + ForwardRoute{ + .timeslice = 0, + .maxTimeslices = 1, + .matcher = {"binding", ConcreteDataMatcher{"TST", "B", 0}}, + .channel = "from_A_to_B", + .policy = nullptr, + }, + ForwardRoute{ + .timeslice = 0, + .maxTimeslices = 1, + .matcher = {"binding", ConcreteDataMatcher{"TST", "A", 0}}, + .channel = "from_A_to_C", + .policy = nullptr, + }}; + + auto findChannelByName = [&channels](std::string const& channelName) -> fair::mq::Channel& { + for (auto& channel : channels) { + if (channel.GetName() == channelName) { + return channel; + } + } + throw std::runtime_error("Channel not found"); + }; + + proxy.bind({}, {}, routes, findChannelByName, nullptr); + + auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq"); + fair::mq::MessagePtr payload1(transport->CreateMessage()); + fair::mq::MessagePtr payload2(transport->CreateMessage()); + auto channelAlloc = o2::pmr::getTransportAllocator(transport.get()); + auto header = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh, dph}); + std::vector> messages; + messages.push_back(std::move(header)); + messages.push_back(std::move(payload1)); + messages.push_back(std::move(payload2)); + auto header2 = o2::pmr::getMessage(o2::header::Stack{channelAlloc, dh2, dph}); + messages.push_back(std::move(header2)); + messages.push_back(transport->CreateMessage()); + + std::vector result(2); + auto span = std::span(messages); + o2::framework::DataProcessingHelpers::routeForwardedMessages(proxy, span, result, copyByDefault, consume); + REQUIRE(result.size() == 2); // Two routes + CHECK(result[0].Size() == 2); // No messages on this route + CHECK(result[1].Size() == 3); +} + TEST_CASE("ForwardInputEOSSingleRoute") { o2::framework::SourceInfoHeader sih{}; From 7b11923549de0c2ebcd4656d8f9f98eda2e7a412 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:56:36 +0100 Subject: [PATCH 077/234] DPL: add callback when inserting in the slot --- Framework/Core/include/Framework/DataRelayer.h | 4 ++++ Framework/Core/src/DataProcessingDevice.cxx | 1 + Framework/Core/src/DataRelayer.cxx | 10 ++++++++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Framework/Core/include/Framework/DataRelayer.h b/Framework/Core/include/Framework/DataRelayer.h index 012b909096317..1e010fc12f3d4 100644 --- a/Framework/Core/include/Framework/DataRelayer.h +++ b/Framework/Core/include/Framework/DataRelayer.h @@ -114,6 +114,9 @@ class DataRelayer using OnDropCallback = std::function&, TimesliceIndex::OldestOutputInfo info)>; + // Callback for when some messages are about to be owned by the the DataRelayer + using OnInsertionCallback = std::function&)>; + /// Prune all the pending entries in the cache. void prunePending(OnDropCallback); /// Prune the cache for a given slot @@ -135,6 +138,7 @@ class DataRelayer InputInfo const& info, size_t nMessages, size_t nPayloads = 1, + OnInsertionCallback onInsertion = nullptr, OnDropCallback onDrop = nullptr); /// This is to set the oldest possible @a timeslice this relayer can diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index 3925359b056b2..343b567d8b852 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -1859,6 +1859,7 @@ void DataProcessingDevice::handleData(ServiceRegistryRef ref, InputChannelInfo& input, nMessages, nPayloadsPerHeader, + nullptr, onDrop); switch (relayed.type) { case DataRelayer::RelayChoice::Type::Backpressured: diff --git a/Framework/Core/src/DataRelayer.cxx b/Framework/Core/src/DataRelayer.cxx index 01e7a2b29fd35..ea2c4c0b73316 100644 --- a/Framework/Core/src/DataRelayer.cxx +++ b/Framework/Core/src/DataRelayer.cxx @@ -436,7 +436,8 @@ DataRelayer::RelayChoice InputInfo const& info, size_t nMessages, size_t nPayloads, - std::function&, TimesliceIndex::OldestOutputInfo)> onDrop) + OnInsertionCallback onInsertion, + OnDropCallback onDrop) { std::scoped_lock lock(mMutex); DataProcessingHeader const* dph = o2::header::get(rawHeader); @@ -482,6 +483,7 @@ DataRelayer::RelayChoice &messages, &nMessages, &nPayloads, + &onInsertion, &cache = mCache, &services = mContext, numInputTypes = mDistinctRoutesIndex.size()](TimesliceId timeslice, int input, TimesliceSlot slot, InputInfo const& info) -> size_t { @@ -512,7 +514,11 @@ DataRelayer::RelayChoice mi += nPayloads; continue; } - target.add([&messages, &mi](size_t i) -> fair::mq::MessagePtr& { return messages[mi + i]; }, nPayloads + 1); + auto span = std::span(messages + mi, messages + mi + nPayloads + 1); + if (onInsertion) { + onInsertion(services, span); + } + target.add([&span](size_t i) -> fair::mq::MessagePtr& { return span[i]; }, nPayloads + 1); mi += nPayloads; saved += nPayloads; } From 1afdd6c49095ffa5a6df708c439e282b9d640abd Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:56:37 +0100 Subject: [PATCH 078/234] DPL: fix how many forwarded parts are needed In principle this is not fatal because the number of routes is always larger / equal than the number of channels by construction. Better safe than sorry. --- Framework/Core/src/DataProcessingHelpers.cxx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Framework/Core/src/DataProcessingHelpers.cxx b/Framework/Core/src/DataProcessingHelpers.cxx index 2f7a1f65f3bd3..87e7c9bf8962f 100644 --- a/Framework/Core/src/DataProcessingHelpers.cxx +++ b/Framework/Core/src/DataProcessingHelpers.cxx @@ -343,9 +343,7 @@ auto DataProcessingHelpers::routeForwardedMessageSet(FairMQDeviceProxy& proxy, const bool copyByDefault, bool consume) -> std::vector { // we collect all messages per forward in a map and send them together - std::vector forwardedParts; - forwardedParts.resize(proxy.getNumForwards()); - std::vector forwardingChoices{}; + std::vector forwardedParts(proxy.getNumForwardChannels()); for (size_t ii = 0, ie = currentSetOfInputs.size(); ii < ie; ++ii) { auto span = std::span(currentSetOfInputs[ii].messages); From 056504e47cb31862baef654a4d847aede982f93a Mon Sep 17 00:00:00 2001 From: shahoian Date: Wed, 14 Jan 2026 22:15:06 +0100 Subject: [PATCH 079/234] Fix ITS/MFT clusterization for some complex shapes, O2-6424. --- .../include/ITSMFTReconstruction/Clusterer.h | 14 ++- .../common/reconstruction/src/Clusterer.cxx | 117 +++++++++++------- 2 files changed, 80 insertions(+), 51 deletions(-) diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h index 960ce2ca33d5b..c66468905d0aa 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h @@ -121,6 +121,10 @@ class Clusterer }; struct ClustererThread { + struct PreCluster { + int head = 0; // index of precluster head in the pixels + int index = 0; + }; int id = -1; Clusterer* parent = nullptr; // parent clusterer // buffers for entries in preClusterIndices in 2 columns, to avoid boundary checks, we reserve @@ -132,12 +136,11 @@ class Clusterer // pixels[].first is the index of the next pixel of the same precluster in the pixels // pixels[].second is the index of the referred pixel in the ChipPixelData (element of mChips) std::vector> pixels; - std::vector preClusterHeads; // index of precluster head in the pixels - std::vector preClusterIndices; uint16_t currCol = 0xffff; ///< Column being processed bool noLeftCol = true; ///< flag that there is no column on the left to check std::array labelsBuff; //! temporary buffer for building cluster labels std::vector pixArrBuff; //! temporary buffer for pattern calc. + std::vector preClusters; //! preclusters info // /// temporary storage for the thread output CompClusCont compClusters; @@ -154,7 +157,7 @@ class Clusterer ///< add cluster at row (entry ip in the ChipPixeData) to the precluster with given index void expandPreCluster(uint32_t ip, uint16_t row, int preClusIndex) { - auto& firstIndex = preClusterHeads[preClusterIndices[preClusIndex]]; + auto& firstIndex = preClusters[preClusters[preClusIndex].index].head; pixels.emplace_back(firstIndex, ip); firstIndex = pixels.size() - 1; curr[row] = preClusIndex; @@ -163,11 +166,10 @@ class Clusterer ///< add new precluster at given row of current column for the fired pixel with index ip in the ChipPixelData void addNewPrecluster(uint32_t ip, uint16_t row) { - preClusterHeads.push_back(pixels.size()); + int lastIndex = preClusters.size(); + preClusters.emplace_back(pixels.size(), lastIndex); // new head does not point yet (-1) on other pixels, store just the entry of the pixel in the ChipPixelData pixels.emplace_back(-1, ip); - int lastIndex = preClusterIndices.size(); - preClusterIndices.push_back(lastIndex); curr[row] = lastIndex; // store index of the new precluster in the current column buffer } diff --git a/Detectors/ITSMFT/common/reconstruction/src/Clusterer.cxx b/Detectors/ITSMFT/common/reconstruction/src/Clusterer.cxx index 15dcc67a8967b..42e535e810a62 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/Clusterer.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/Clusterer.cxx @@ -133,15 +133,17 @@ void Clusterer::process(int nThreads, PixelReader& reader, CompClusCont* compClu if (stat.firstChip == chid) { thrStatIdx[ith]++; chid += stat.nChips; // next chip to look - const auto clbeg = mThreads[ith]->compClusters.begin() + stat.firstClus; - auto szold = compClus->size(); - compClus->insert(compClus->end(), clbeg, clbeg + stat.nClus); - if (patterns) { - const auto ptbeg = mThreads[ith]->patterns.begin() + stat.firstPatt; - patterns->insert(patterns->end(), ptbeg, ptbeg + stat.nPatt); - } - if (labelsCl) { - labelsCl->mergeAtBack(mThreads[ith]->labels, stat.firstClus, stat.nClus); + if (stat.nClus > 0) { + const auto clbeg = mThreads[ith]->compClusters.begin() + stat.firstClus; + auto szold = compClus->size(); + compClus->insert(compClus->end(), clbeg, clbeg + stat.nClus); + if (patterns) { + const auto ptbeg = mThreads[ith]->patterns.begin() + stat.firstPatt; + patterns->insert(patterns->end(), ptbeg, ptbeg + stat.nPatt); + } + if (labelsCl) { + labelsCl->mergeAtBack(mThreads[ith]->labels, stat.firstClus, stat.nClus); + } } } } @@ -214,14 +216,22 @@ void Clusterer::ClustererThread::finishChip(ChipPixelData* curChipData, CompClus PatternCont* patternsPtr, const ConstMCTruth* labelsDigPtr, MCTruth* labelsClusPtr) { const auto& pixData = curChipData->getData(); - for (int i1 = 0; i1 < preClusterHeads.size(); ++i1) { - auto ci = preClusterIndices[i1]; + int nPreclusters = preClusters.size(); + // account for the eventual reindexing of preClusters: Id2 might have been reindexed to Id1, which later was reindexed to Id0 + for (int i = 1; i < nPreclusters; i++) { + if (preClusters[i].index != i) { // reindexing is always done towards smallest index + preClusters[i].index = preClusters[preClusters[i].index].index; + } + } + for (int i1 = 0; i1 < nPreclusters; ++i1) { + auto& preCluster = preClusters[i1]; + auto ci = preCluster.index; if (ci < 0) { continue; } BBox bbox(curChipData->getChipID()); int nlab = 0; - int next = preClusterHeads[i1]; + int next = preCluster.head; pixArrBuff.clear(); while (next >= 0) { const auto& pixEntry = pixels[next]; @@ -237,12 +247,13 @@ void Clusterer::ClustererThread::finishChip(ChipPixelData* curChipData, CompClus } next = pixEntry.first; } - preClusterIndices[i1] = -1; - for (int i2 = i1 + 1; i2 < preClusterHeads.size(); ++i2) { - if (preClusterIndices[i2] != ci) { + preCluster.index = -1; + for (int i2 = i1 + 1; i2 < nPreclusters; ++i2) { + auto& preCluster2 = preClusters[i2]; + if (preCluster2.index != ci) { continue; } - next = preClusterHeads[i2]; + next = preCluster2.head; while (next >= 0) { const auto& pixEntry = pixels[next]; const auto pix = pixData[pixEntry.second]; // PixelData @@ -257,7 +268,7 @@ void Clusterer::ClustererThread::finishChip(ChipPixelData* curChipData, CompClus } next = pixEntry.first; } - preClusterIndices[i2] = -1; + preCluster2.index = -1; } if (bbox.isAcceptableSize()) { parent->streamCluster(pixArrBuff, &labelsBuff, bbox, parent->mPattIdConverter, compClusPtr, patternsPtr, labelsClusPtr, nlab); @@ -344,18 +355,15 @@ void Clusterer::ClustererThread::initChip(const ChipPixelData* curChipData, uint prev = column1 + 1; curr = column2 + 1; resetColumn(curr); - pixels.clear(); - preClusterHeads.clear(); - preClusterIndices.clear(); + preClusters.clear(); auto pix = curChipData->getData()[first]; currCol = pix.getCol(); curr[pix.getRowDirect()] = 0; // can use getRowDirect since the pixel is not masked // start the first pre-cluster - preClusterHeads.push_back(0); - preClusterIndices.push_back(0); + preClusters.emplace_back(); pixels.emplace_back(-1, first); // id of current pixel - noLeftCol = true; // flag that there is no column on the left to check yet + noLeftCol = true; } //__________________________________________________ @@ -378,39 +386,58 @@ void Clusterer::ClustererThread::updateChip(const ChipPixelData* curChipData, ui currCol = pix.getCol(); } - Bool_t orphan = true; - if (noLeftCol) { // check only the row above if (curr[row - 1] >= 0) { expandPreCluster(ip, row, curr[row - 1]); // attach to the precluster of the previous row - return; + } else { + addNewPrecluster(ip, row); // start new precluster } } else { + // row above should be always checked + int nnb = 0, lowestIndex = curr[row - 1], lowestNb = 0, *nbrCol[4], nbrRow[4]; + if (lowestIndex >= 0) { + nbrCol[nnb] = curr; + nbrRow[nnb++] = row - 1; + } else { + lowestIndex = 0x7ffff; + lowestNb = -1; + } #ifdef _ALLOW_DIAGONAL_ALPIDE_CLUSTERS_ - int neighbours[]{curr[row - 1], prev[row], prev[row + 1], prev[row - 1]}; -#else - int neighbours[]{curr[row - 1], prev[row]}; -#endif - for (auto pci : neighbours) { - if (pci < 0) { - continue; + for (int i : {-1, 0, 1}) { + auto v = prev[row + i]; + if (v >= 0) { + nbrCol[nnb] = prev; + nbrRow[nnb] = row + i; + if (v < lowestIndex) { + lowestIndex = v; + lowestNb = nnb; + } + nnb++; } - if (orphan) { - expandPreCluster(ip, row, pci); // attach to the adjascent precluster - orphan = false; - continue; + } +#else + if (prev[row] >= 0) { + nbrCol[nnb] = prev; + nbrRow[nnb] = row; + if (prev[row] < lowestIndex) { + lowestIndex = v; + lowestNb = nnb; } - // reassign precluster index to smallest one - if (preClusterIndices[pci] < preClusterIndices[curr[row]]) { - preClusterIndices[curr[row]] = preClusterIndices[pci]; - } else { - preClusterIndices[pci] = preClusterIndices[curr[row]]; + nnb++; + } +#endif + if (!nnb) { // no neighbours, create new precluster + addNewPrecluster(ip, row); // start new precluster + } else { + expandPreCluster(ip, row, lowestIndex); // attach to the adjascent precluster with smallest index + if (nnb > 1) { + for (int inb = 0; inb < nnb; inb++) { // reassign precluster index to smallest one, replicating updated values to columns caches + auto& prevIndex = (nbrCol[inb])[nbrRow[inb]]; + prevIndex = preClusters[prevIndex].index = lowestIndex; + } } } } - if (orphan) { - addNewPrecluster(ip, row); // start new precluster - } } //__________________________________________________ From eb3d49c31d23bd8d0c523ae7916c9ad5ba0d081c Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Wed, 14 Jan 2026 09:27:55 +0100 Subject: [PATCH 080/234] DPL Analysis: do not override error-handler reader for MC injected workflows --- Framework/Core/src/ArrowSupport.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Framework/Core/src/ArrowSupport.cxx b/Framework/Core/src/ArrowSupport.cxx index c0280b144e146..c403d983325dc 100644 --- a/Framework/Core/src/ArrowSupport.cxx +++ b/Framework/Core/src/ArrowSupport.cxx @@ -684,8 +684,10 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() workflow.erase(reader); } else { // load reader algorithm before deployment - auto&& algo = PluginManager::loadAlgorithmFromPlugin("O2FrameworkAnalysisSupport", "ROOTFileReader", ctx); - reader->algorithm = CommonDataProcessors::wrapWithTimesliceConsumption(algo); + auto mctracks2aod = std::find_if(workflow.begin(), workflow.end(), [](auto const& x) { return x.name == "mctracks-to-aod"; }); + if (mctracks2aod == workflow.end()) { // add normal reader algorithm only if no on-the-fly generator is injected + reader->algorithm = CommonDataProcessors::wrapWithTimesliceConsumption(PluginManager::loadAlgorithmFromPlugin("O2FrameworkAnalysisSupport", "ROOTFileReader", ctx)); + } // otherwise the algorithm was set in injectServiceDevices } } From 5cce90740c429898ff787e978e3f24573161ed9e Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Wed, 14 Jan 2026 13:21:42 +0100 Subject: [PATCH 081/234] Fix embedding test --- prodtests/full_system_test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prodtests/full_system_test.sh b/prodtests/full_system_test.sh index a799afbbbfd3d..8ee8b5992b846 100755 --- a/prodtests/full_system_test.sh +++ b/prodtests/full_system_test.sh @@ -71,7 +71,7 @@ else fi FST_MC_ENGINE=${FST_MC_ENGINE:-TGeant4} FST_EMBEDDING_CONFIG=${FST_EMBEDDING_CONFIG:-GeneratorPythia8.config=$O2_ROOT/prodtests/full-system-test/pythia8.cfg} -DO_EMBEDDING=${DO_EMBEDDING:-0} +DO_EMBEDDING=${DO_EMBEDDING:-1} if [[ $DO_EMBEDDING == 0 ]]; then SIM_SOURCES="o2sim" else @@ -139,7 +139,7 @@ fi taskwrapper sim.log o2-sim ${FST_BFIELD+--field=}${FST_BFIELD} --seed $O2SIMSEED -n $NEvents --configKeyValues "\"$SIMOPTKEY\"" -g ${FST_GENERATOR} -e ${FST_MC_ENGINE} -j $NJOBS --run ${RUNNUMBER} -o o2sim if [[ $DO_EMBEDDING == 1 ]]; then - taskwrapper embed.log o2-sim ${FST_BFIELD+--field=}${FST_BFIELD} -j $NJOBS --run ${RUNNUMBER} -n $NEvents -g pythia8pp -e ${FST_MC_ENGINE} -o sig --configKeyValues ${FST_EMBEDDING_CONFIG} --embedIntoFile o2sim_Kine.root + taskwrapper embed.log o2-sim ${FST_BFIELD+--field=}${FST_BFIELD} -j $NJOBS --run ${RUNNUMBER} -n $NEvents -g pythia8pp -e ${FST_MC_ENGINE} -o sig --configKeyValues ${FST_EMBEDDING_CONFIG} --embedIntoFile o2sim_MCHeader.root fi taskwrapper digi.log o2-sim-digitizer-workflow -n $NEvents ${DIGIQED} ${NOMCLABELS} --sims ${SIM_SOURCES} --tpc-lanes $((NJOBS < 36 ? NJOBS : 36)) --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} ${DIGITOPT} --configKeyValues "\"${DIGITOPTKEY}\"" --interactionRate $FST_COLRATE --early-forward-policy always [[ $SPLITTRDDIGI == "1" ]] && taskwrapper digiTRD.log o2-sim-digitizer-workflow -n $NEvents ${NOMCLABELS} --sims ${SIM_SOURCES} --onlyDet TRD --trd-digit-downscaling ${DIGITDOWNSCALINGTRD} --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} --incontext collisioncontext.root --configKeyValues "\"${DIGITOPTKEYTRD}\"" --early-forward-policy always From 8c0bd3ce631100e5ee0bdc61e5d430ef1110cc29 Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Thu, 15 Jan 2026 13:27:17 +0100 Subject: [PATCH 082/234] Switch off default embedding --- prodtests/full_system_test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prodtests/full_system_test.sh b/prodtests/full_system_test.sh index 8ee8b5992b846..bf235a500cd8b 100755 --- a/prodtests/full_system_test.sh +++ b/prodtests/full_system_test.sh @@ -71,7 +71,7 @@ else fi FST_MC_ENGINE=${FST_MC_ENGINE:-TGeant4} FST_EMBEDDING_CONFIG=${FST_EMBEDDING_CONFIG:-GeneratorPythia8.config=$O2_ROOT/prodtests/full-system-test/pythia8.cfg} -DO_EMBEDDING=${DO_EMBEDDING:-1} +DO_EMBEDDING=${DO_EMBEDDING:-0} if [[ $DO_EMBEDDING == 0 ]]; then SIM_SOURCES="o2sim" else From 34d96168b97ba4c073585eafdcd3c9c93b271f8d Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Thu, 15 Jan 2026 14:43:39 +0100 Subject: [PATCH 083/234] DPL Analysis: fix for slice index builder resetting its caches in a wrong order --- Framework/Core/src/IndexBuilderHelpers.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Framework/Core/src/IndexBuilderHelpers.cxx b/Framework/Core/src/IndexBuilderHelpers.cxx index d7231f72cbee8..0943dea42169c 100644 --- a/Framework/Core/src/IndexBuilderHelpers.cxx +++ b/Framework/Core/src/IndexBuilderHelpers.cxx @@ -161,14 +161,14 @@ SliceBuilder::SliceBuilder(std::shared_ptr source, arrow::M void SliceBuilder::reset(std::shared_ptr source) { + mValues = nullptr; + mCounts = nullptr; + mListBuilder->Reset(); + mValuePos = 0; static_cast(this)->reset(source); if (!preSlice().ok()) { throw framework::runtime_error("Cannot pre-slice the source for slice-index building"); } - mListBuilder->Reset(); - mValues = nullptr; - mCounts = nullptr; - mValuePos = 0; } bool SliceBuilder::find(int idx) From 7245d49faf8a6e7cfd29d81a44f6cda5b52dfa2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Piero=C5=BCak?= <94726725+wpierozak@users.noreply.github.com> Date: Thu, 15 Jan 2026 17:11:35 +0100 Subject: [PATCH 084/234] AFIT-1 FV0 digitzer dead channel map (#14908) * FIT: added DeadChannelMap to FV0 Digitzier * FIT: changed default value of disable-dead-channel-map option for FV0 digitizer to false * FIT: included CCDBParamSpec.h in FV0DigitizerSpec.cxx * FIT: Fixed typo in FV0DigitizerSpec.cxx * FIT: change inputs to FV0 digitizer --- .../include/FV0Simulation/Digitizer.h | 4 +++ .../FIT/FV0/simulation/src/Digitizer.cxx | 5 ++++ .../src/FV0DigitizerSpec.cxx | 30 ++++++++++++++++--- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/Detectors/FIT/FV0/simulation/include/FV0Simulation/Digitizer.h b/Detectors/FIT/FV0/simulation/include/FV0Simulation/Digitizer.h index 6956d8126ce53..b97893822c9d8 100644 --- a/Detectors/FIT/FV0/simulation/include/FV0Simulation/Digitizer.h +++ b/Detectors/FIT/FV0/simulation/include/FV0Simulation/Digitizer.h @@ -14,6 +14,7 @@ #include "CommonDataFormat/InteractionRecord.h" #include "DataFormatsFV0/Digit.h" +#include "DataFormatsFIT/DeadChannelMap.h" #include "DataFormatsFV0/ChannelData.h" #include "DataFormatsFV0/MCLabel.h" #include "FV0Simulation/Detector.h" @@ -51,6 +52,7 @@ class Digitizer void setEventId(Int_t id) { mEventId = id; } void setSrcId(Int_t id) { mSrcId = id; } void setInteractionRecord(const InteractionTimeRecord& ir) { mIntRecord = ir; } + void setDeadChannelMap(o2::fit::DeadChannelMap const* deadChannelMap) { mDeadChannelMap = deadChannelMap; }; void process(const std::vector& hits, std::vector& digitsBC, std::vector& digitsCh, std::vector& digitsTrig, @@ -132,6 +134,8 @@ class Digitizer BCCache mLastBCCache; // buffer for the last BC std::array mCfdStartIndex; // start indices for the CFD detector + o2::fit::DeadChannelMap const* mDeadChannelMap = nullptr; + /// Internal helper methods related to conversion of energy-deposition into el. signal Int_t SimulateLightYield(Int_t pmt, Int_t nPhot) const; Float_t SimulateTimeCfd(int& startIndex, const ChannelDigitF& pulseLast, const ChannelDigitF& pulse) const; diff --git a/Detectors/FIT/FV0/simulation/src/Digitizer.cxx b/Detectors/FIT/FV0/simulation/src/Digitizer.cxx index 1c94b14f029cf..8c1d2dc8824e2 100644 --- a/Detectors/FIT/FV0/simulation/src/Digitizer.cxx +++ b/Detectors/FIT/FV0/simulation/src/Digitizer.cxx @@ -98,6 +98,11 @@ void Digitizer::process(const std::vector& hits, for (auto ids : hitIdx) { const auto& hit = hits[ids]; Int_t detId = hit.GetDetectorID(); + + if (mDeadChannelMap && !mDeadChannelMap->isChannelAlive(detId)) { + continue; + } + Double_t hitEdep = hit.GetHitValue() * 1e3; // convert to MeV Float_t const hitTime = hit.GetTime() * 1e9; // convert to ns // TODO: check how big is inaccuracy if more than 1 'below-threshold' particles hit the same detector cell diff --git a/Steer/DigitizerWorkflow/src/FV0DigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/FV0DigitizerSpec.cxx index 28f259c11162b..8197b1be1847b 100644 --- a/Steer/DigitizerWorkflow/src/FV0DigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/FV0DigitizerSpec.cxx @@ -11,6 +11,7 @@ #include "FV0DigitizerSpec.h" #include "DataFormatsFV0/ChannelData.h" +#include "DataFormatsFIT/DeadChannelMap.h" #include "DataFormatsFV0/Digit.h" #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" @@ -30,6 +31,7 @@ #include "SimulationDataFormat/MCCompLabel.h" #include "DetectorsBase/BaseDPLDigitizer.h" #include "DetectorsRaw/HBFUtils.h" +#include "Framework/CCDBParamSpec.h" #include using namespace o2::framework; @@ -53,6 +55,16 @@ class FV0DPLDigitizerTask : public o2::base::BaseDPLDigitizer LOG(debug) << "FV0DPLDigitizerTask:init"; mDigitizer.init(); mDisableQED = ic.options().get("disable-qed"); //TODO: QED implementation to be tested + mUseDeadChannelMap = !ic.options().get("disable-dead-channel-map"); + mUpdateDeadChannelMap = mUseDeadChannelMap; + } + + void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) + { + // Initialize the dead channel map only once + if (matcher == ConcreteDataMatcher("FV0", "DeadChannelMap", 0)) { + mUpdateDeadChannelMap = false; + } } void run(framework::ProcessingContext& pc) @@ -67,6 +79,11 @@ class FV0DPLDigitizerTask : public o2::base::BaseDPLDigitizer context->initSimChains(o2::detectors::DetID::FV0, mSimChains); const bool withQED = context->isQEDProvided() && !mDisableQED; //TODO: QED implementation to be tested + if (mUseDeadChannelMap && mUpdateDeadChannelMap) { + auto deadChannelMap = pc.inputs().get("fv0deadchannelmap"); + mDigitizer.setDeadChannelMap(deadChannelMap.get()); + } + mDigitizer.setTimeStamp(context->getGRP().getTimeStart()); auto& irecords = context->getEventRecords(withQED); //TODO: QED implementation to be tested @@ -131,6 +148,8 @@ class FV0DPLDigitizerTask : public o2::base::BaseDPLDigitizer private: bool mFinished = false; + bool mUseDeadChannelMap = true; + bool mUpdateDeadChannelMap = true; Digitizer mDigitizer; std::vector mSimChains; std::vector mDigitsCh; @@ -159,16 +178,19 @@ o2::framework::DataProcessorSpec getFV0DigitizerSpec(int channel, bool mctruth) } outputs.emplace_back("FV0", "ROMode", 0, Lifetime::Timeframe); + std::vector inputs; + inputs.emplace_back("fv0deadchannelmap", "FV0", "DeadChannelMap", 0, Lifetime::Condition, ccdbParamSpec("FV0/Calib/DeadChannelMap")); + inputs.emplace_back("collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast(channel), Lifetime::Timeframe); return DataProcessorSpec{ "FV0Digitizer", - Inputs{InputSpec{"collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast(channel), Lifetime::Timeframe}}, - + inputs, outputs, AlgorithmSpec{adaptFromTask()}, Options{{"pileup", VariantType::Int, 1, {"whether to run in continuous time mode"}}, - {"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}}}}; - //Options{{"pileup", VariantType::Int, 1, {"whether to run in continuous time mode"}}}}; + {"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}}, + {"disable-dead-channel-map", o2::framework::VariantType::Bool, false, {"Don't mask dead channels"}}}}; + // Options{{"pileup", VariantType::Int, 1, {"whether to run in continuous time mode"}}}}; } } // end namespace fv0 From 7aa1bbc3f97df804c61ce31f0aeed65d81e520b7 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Thu, 15 Jan 2026 19:45:39 +0100 Subject: [PATCH 085/234] DPL Analysis: Rework table input record extraction (#14944) --- .../src/AODJAlienReaderHelpers.cxx | 23 ------- .../AnalysisSupport/src/AODReaderHelpers.cxx | 25 +++++--- .../AnalysisSupport/src/AODWriterHelpers.cxx | 7 +-- .../CCDBSupport/src/AnalysisCCDBHelpers.cxx | 5 +- Framework/Core/include/Framework/ASoA.h | 63 ++++++++++++++++--- .../Core/include/Framework/AnalysisHelpers.h | 7 ++- .../Core/include/Framework/AnalysisManagers.h | 8 +-- .../Core/include/Framework/AnalysisTask.h | 8 +-- .../Framework/ArrowTableSlicingCache.h | 13 +++- .../include/Framework/ConcreteDataMatcher.h | 6 +- .../Core/include/Framework/DataSpecUtils.h | 6 ++ .../Core/include/Framework/DataSpecViews.h | 7 +++ .../Core/include/Framework/GroupSlicer.h | 2 +- .../Core/include/Framework/InputRecord.h | 22 +++++++ Framework/Core/src/AnalysisHelpers.cxx | 10 +-- Framework/Core/src/ArrowSupport.cxx | 4 +- Framework/Core/src/ArrowTableSlicingCache.cxx | 21 ++++--- Framework/Core/src/DataSpecUtils.cxx | 34 +++++++++- Framework/Core/src/IndexJSONHelpers.cxx | 12 +++- Framework/Core/src/InputRecord.cxx | 5 ++ Framework/Core/test/benchmark_EventMixing.cxx | 6 +- Framework/Core/test/test_ASoA.cxx | 5 +- Framework/Core/test/test_GroupSlicer.cxx | 33 ++++++---- Framework/TestWorkflows/CMakeLists.txt | 4 ++ .../TestWorkflows/src/o2TestHistograms.cxx | 6 +- .../TestWorkflows/src/o2TestMultisource.cxx | 47 ++++++++++++++ 26 files changed, 286 insertions(+), 103 deletions(-) create mode 100644 Framework/TestWorkflows/src/o2TestMultisource.cxx diff --git a/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx b/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx index b532c51b8d307..cde6c85f2c624 100644 --- a/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx +++ b/Framework/AnalysisSupport/src/AODJAlienReaderHelpers.cxx @@ -98,29 +98,6 @@ using o2::monitoring::tags::Value; namespace o2::framework::readers { -auto setEOSCallback(InitContext& ic) -{ - ic.services().get().set( - [](EndOfStreamContext& eosc) { - auto& control = eosc.services().get(); - control.endOfStream(); - control.readyToQuit(QuitRequest::Me); - }); -} - -template -static inline auto extractTypedOriginal(ProcessingContext& pc) -{ - /// FIXME: this should be done in invokeProcess() as some of the originals may be compound tables - return O{pc.inputs().get(aod::MetadataTrait::metadata::tableLabel())->asArrowTable()}; -} - -template -static inline auto extractOriginalsTuple(framework::pack, ProcessingContext& pc) -{ - return std::make_tuple(extractTypedOriginal(pc)...); -} - AlgorithmSpec AODJAlienReaderHelpers::rootFileReaderCallback(ConfigContext const& ctx) { // aod-parent-base-path-replacement is now a workflow option, so it needs to be diff --git a/Framework/AnalysisSupport/src/AODReaderHelpers.cxx b/Framework/AnalysisSupport/src/AODReaderHelpers.cxx index 7f08dd0b36a64..485f3fa69edad 100644 --- a/Framework/AnalysisSupport/src/AODReaderHelpers.cxx +++ b/Framework/AnalysisSupport/src/AODReaderHelpers.cxx @@ -18,6 +18,7 @@ #include "Framework/DataProcessingHelpers.h" #include "Framework/AlgorithmSpec.h" #include "Framework/DataSpecUtils.h" +#include "Framework/DataSpecViews.h" #include "Framework/ConfigContext.h" #include "Framework/DanglingEdgesContext.h" @@ -29,6 +30,7 @@ struct Buildable { bool exclusive = false; std::string binding; std::vector labels; + std::vector matchers; header::DataOrigin origin; header::DataDescription description; header::DataHeader::SubSpecificationType version; @@ -52,6 +54,7 @@ struct Buildable { for (auto const& r : records) { labels.emplace_back(r.label); + matchers.emplace_back(r.matcher); } outputSchema = std::make_shared([](std::vector const& recs) { std::vector> fields; @@ -68,6 +71,7 @@ struct Buildable { return { exclusive, labels, + matchers, records, outputSchema, origin, @@ -105,6 +109,7 @@ namespace struct Spawnable { std::string binding; std::vector labels; + std::vector matchers; std::vector projectors; std::vector> expressions; std::shared_ptr outputSchema; @@ -132,14 +137,17 @@ struct Spawnable { o2::framework::addLabelToSchema(outputSchema, binding.c_str()); std::vector> schemas; - for (auto& i : spec.metadata) { - if (i.name.starts_with("input-schema:")) { - labels.emplace_back(i.name.substr(13)); - iws.clear(); - auto json = i.defaultValue.get(); - iws.str(json); - schemas.emplace_back(ArrowJSONHelpers::read(iws)); - } + for (auto const& i : spec.metadata | views::filter_string_params_starts_with("input-schema:")) { + labels.emplace_back(i.name.substr(13)); + iws.clear(); + auto json = i.defaultValue.get(); + iws.str(json); + schemas.emplace_back(ArrowJSONHelpers::read(iws)); + } + for (auto const& i : spec.metadata | views::filter_string_params_starts_with("input:") | std::ranges::views::transform([](auto const& param) { + return DataSpecUtils::fromMetadataString(param.defaultValue.template get()); + })) { + matchers.emplace_back(std::get(i.matcher)); } std::vector> fields; @@ -169,6 +177,7 @@ struct Spawnable { return { binding, labels, + matchers, expressions, makeProjector(), outputSchema, diff --git a/Framework/AnalysisSupport/src/AODWriterHelpers.cxx b/Framework/AnalysisSupport/src/AODWriterHelpers.cxx index 5a43683afd364..d868b7498fb76 100644 --- a/Framework/AnalysisSupport/src/AODWriterHelpers.cxx +++ b/Framework/AnalysisSupport/src/AODWriterHelpers.cxx @@ -185,13 +185,12 @@ AlgorithmSpec AODWriterHelpers::getOutputTTreeWriter(ConfigContext const& ctx) } // get the TableConsumer and corresponding arrow table - auto msg = pc.inputs().get(ref.spec->binding); - if (msg.header == nullptr) { + if (ref.header == nullptr) { LOGP(error, "No header for message {}:{}", ref.spec->binding, DataSpecUtils::describe(*ref.spec)); continue; } - auto s = pc.inputs().get(ref.spec->binding); - auto table = s->asArrowTable(); + + auto table = pc.inputs().get(std::get(ref.spec->matcher))->asArrowTable(); if (!table->Validate().ok()) { LOGP(warning, "The table \"{}\" is not valid and will not be saved!", tableName); continue; diff --git a/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx b/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx index fcc856669cd92..9ec911518f754 100644 --- a/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx +++ b/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx @@ -83,6 +83,7 @@ AlgorithmSpec AnalysisCCDBHelpers::fetchFromCCDB(ConfigContext const& ctx) if (m.name.starts_with("input:")) { auto name = m.name.substr(6); schemaMetadata->Append("sourceTable", name); + schemaMetadata->Append("sourceMatcher", DataSpecUtils::describe(std::get(DataSpecUtils::fromMetadataString(m.defaultValue.get()).matcher))); continue; } // Ignore the non ccdb: entries @@ -109,13 +110,13 @@ AlgorithmSpec AnalysisCCDBHelpers::fetchFromCCDB(ConfigContext const& ctx) for (auto& schema : schemas) { std::vector ops; auto inputBinding = *schema->metadata()->Get("sourceTable"); + auto inputMatcher = DataSpecUtils::fromString(*schema->metadata()->Get("sourceMatcher")); auto outRouteDesc = *schema->metadata()->Get("outputRoute"); std::string outBinding = *schema->metadata()->Get("outputBinding"); O2_SIGNPOST_EVENT_EMIT_INFO(ccdb, sid, "fetchFromAnalysisCCDB", "Fetching CCDB objects for %{public}s's columns with timestamps from %{public}s and putting them in route %{public}s", outBinding.c_str(), inputBinding.c_str(), outRouteDesc.c_str()); - auto ref = inputs.get(inputBinding); - auto table = ref->asArrowTable(); + auto table = inputs.get(inputMatcher)->asArrowTable(); // FIXME: make the fTimestamp column configurable. auto timestampColumn = table->GetColumnByName("fTimestamp"); O2_SIGNPOST_EVENT_EMIT_INFO(ccdb, sid, "fetchFromAnalysisCCDB", diff --git a/Framework/Core/include/Framework/ASoA.h b/Framework/Core/include/Framework/ASoA.h index 43079a4634e97..ec02c7e47132b 100644 --- a/Framework/Core/include/Framework/ASoA.h +++ b/Framework/Core/include/Framework/ASoA.h @@ -12,6 +12,7 @@ #ifndef O2_FRAMEWORK_ASOA_H_ #define O2_FRAMEWORK_ASOA_H_ +#include "Framework/ConcreteDataMatcher.h" #include "Framework/Pack.h" // IWYU pragma: export #include "Framework/FunctionalHelpers.h" // IWYU pragma: export #include "Headers/DataHeader.h" // IWYU pragma: export @@ -375,6 +376,12 @@ consteval const char* signature() return o2::aod::Hash::str; } +template +constexpr framework::ConcreteDataMatcher matcher() +{ + return {origin(), description(signature()), R.version}; +} + /// hash identification concepts template concept is_aod_hash = requires(T t) { t.hash; t.str; }; @@ -1393,6 +1400,12 @@ static constexpr std::pair hasKey(std::string const& key) return {hasColumnForKey(typename aod::MetadataTrait>::metadata::columns{}, key), aod::label()}; } +template +static constexpr std::pair hasKeyM(std::string const& key) +{ + return {hasColumnForKey(typename aod::MetadataTrait>::metadata::columns{}, key), aod::matcher()}; +} + template static constexpr auto haveKey(framework::pack, std::string const& key) { @@ -1427,6 +1440,31 @@ static constexpr std::string getLabelFromTypeForKey(std::string const& key) O2_BUILTIN_UNREACHABLE(); } +template +static constexpr framework::ConcreteDataMatcher getMatcherFromTypeForKey(std::string const& key) +{ + if constexpr (T::originals.size() == 1) { + auto locate = hasKeyM(key); + if (locate.first) { + return locate.second; + } + } else { + auto locate = [&](std::index_sequence) { + return std::vector{hasKeyM(key)...}; + }(std::make_index_sequence{}); + auto it = std::find_if(locate.begin(), locate.end(), [](auto const& x) { return x.first; }); + if (it != locate.end()) { + return it->second; + } + } + if constexpr (!OPT) { + notFoundColumn(getLabelFromType>().data(), key.data()); + } else { + return framework::ConcreteDataMatcher{header::DataOrigin{"AOD"}, header::DataDescription{"[MISSING]"}, 0}; + } + O2_BUILTIN_UNREACHABLE(); +} + template consteval static bool hasIndexTo(framework::pack&&) { @@ -1477,7 +1515,10 @@ struct PreslicePolicyGeneral : public PreslicePolicyBase { std::span getSliceFor(int value) const; }; -template +template +concept is_preslice_policy = std::derived_from; + +template struct PresliceBase : public Policy { constexpr static bool optional = OPT; using target_t = T; @@ -1485,7 +1526,7 @@ struct PresliceBase : public Policy { const std::string binding; PresliceBase(expressions::BindingNode index_) - : Policy{PreslicePolicyBase{{o2::soa::getLabelFromTypeForKey(std::string{index_.name})}, Entry(o2::soa::getLabelFromTypeForKey(std::string{index_.name}), std::string{index_.name})}, {}} + : Policy{PreslicePolicyBase{{o2::soa::getLabelFromTypeForKey(std::string{index_.name})}, Entry(o2::soa::getLabelFromTypeForKey(std::string{index_.name}), o2::soa::getMatcherFromTypeForKey(std::string{index_.name}), std::string{index_.name})}, {}} { } @@ -1520,7 +1561,11 @@ template using PresliceOptional = PresliceBase; template -concept is_preslice = std::derived_from; +concept is_preslice = std::derived_from&& + requires(T) +{ + T::optional; +}; /// Can be user to group together a number of Preslice declaration /// to avoid the limit of 100 data members per task @@ -1667,10 +1712,10 @@ auto doFilteredSliceBy(T const* table, o2::framework::PresliceBase +template auto doSliceByCached(T const* table, framework::expressions::BindingNode const& node, int value, o2::framework::SliceCache& cache) { - auto localCache = cache.ptr->getCacheFor({o2::soa::getLabelFromTypeForKey(node.name), node.name}); + auto localCache = cache.ptr->getCacheFor({"", o2::soa::getMatcherFromTypeForKey(node.name), node.name}); auto [offset, count] = localCache.getSliceFor(value); auto t = typename T::self_t({table->asArrowTable()->Slice(static_cast(offset), count)}, static_cast(offset)); if (t.tableSize() != 0) { @@ -1679,19 +1724,19 @@ auto doSliceByCached(T const* table, framework::expressions::BindingNode const& return t; } -template +template auto doFilteredSliceByCached(T const* table, framework::expressions::BindingNode const& node, int value, o2::framework::SliceCache& cache) { - auto localCache = cache.ptr->getCacheFor({o2::soa::getLabelFromTypeForKey(node.name), node.name}); + auto localCache = cache.ptr->getCacheFor({"", o2::soa::getMatcherFromTypeForKey(node.name), node.name}); auto [offset, count] = localCache.getSliceFor(value); auto slice = table->asArrowTable()->Slice(static_cast(offset), count); return prepareFilteredSlice(table, slice, offset); } -template +template auto doSliceByCachedUnsorted(T const* table, framework::expressions::BindingNode const& node, int value, o2::framework::SliceCache& cache) { - auto localCache = cache.ptr->getCacheUnsortedFor({o2::soa::getLabelFromTypeForKey(node.name), node.name}); + auto localCache = cache.ptr->getCacheUnsortedFor({"", o2::soa::getMatcherFromTypeForKey(node.name), node.name}); if constexpr (soa::is_filtered_table) { auto t = typename T::self_t({table->asArrowTable()}, localCache.getSliceFor(value)); if (t.tableSize() != 0) { diff --git a/Framework/Core/include/Framework/AnalysisHelpers.h b/Framework/Core/include/Framework/AnalysisHelpers.h index 3666fe1299489..a01d14b6632a9 100644 --- a/Framework/Core/include/Framework/AnalysisHelpers.h +++ b/Framework/Core/include/Framework/AnalysisHelpers.h @@ -30,6 +30,7 @@ namespace o2::soa { struct IndexRecord { std::string label; + framework::ConcreteDataMatcher matcher; std::string columnLabel; IndexKind kind; int pos; @@ -142,6 +143,7 @@ std::vector> extractSources(ProcessingContext& pc, struct Spawner { std::string binding; std::vector labels; + std::vector matchers; std::vector> expressions; std::shared_ptr projector = nullptr; std::shared_ptr schema = nullptr; @@ -157,6 +159,7 @@ struct Spawner { struct Builder { bool exclusive; std::vector labels; + std::vector matchers; std::vector records; std::shared_ptr outputSchema; header::DataOrigin origin; @@ -258,9 +261,9 @@ inline constexpr auto getIndexMapping() ([&idx]() mutable { constexpr auto pos = o2::aod::MetadataTrait>::metadata::template getIndexPosToKey(); if constexpr (pos == -1) { - idx.emplace_back(o2::aod::label(), C::columnLabel(), IndexKind::IdxSelf, pos); + idx.emplace_back(o2::aod::label(), o2::aod::matcher(), C::columnLabel(), IndexKind::IdxSelf, pos); } else { - idx.emplace_back(o2::aod::label(), C::columnLabel(), getIndexKind(), pos); + idx.emplace_back(o2::aod::label(), o2::aod::matcher(), C::columnLabel(), getIndexKind(), pos); } }.template operator()>(), ...); diff --git a/Framework/Core/include/Framework/AnalysisManagers.h b/Framework/Core/include/Framework/AnalysisManagers.h index fbb499940b9b9..5112e3659f4aa 100644 --- a/Framework/Core/include/Framework/AnalysisManagers.h +++ b/Framework/Core/include/Framework/AnalysisManagers.h @@ -38,7 +38,7 @@ template refs> static inline auto extractOriginals(ProcessingContext& pc) { return [&](std::index_sequence) -> std::vector> { - return {pc.inputs().get(o2::aod::label())->asArrowTable()...}; + return {pc.inputs().get(o2::aod::matcher())->asArrowTable()...}; }(std::make_index_sequence()); } } // namespace @@ -151,7 +151,7 @@ template concept with_base_table = requires { T::base_specs(); }; template -bool requestInputs(std::vector& inputs, T const& entity) +bool requestInputs(std::vector& inputs, T const& /*entity*/) { auto base_specs = T::base_specs(); for (auto base_spec : base_specs) { @@ -586,7 +586,7 @@ bool registerCache(T& preslice, Cache& bsks, Cache&) return true; } } - auto locate = std::find_if(bsks.begin(), bsks.end(), [&](auto const& entry) { return (entry.binding == preslice.bindingKey.binding) && (entry.key == preslice.bindingKey.key); }); + auto locate = std::find(bsks.begin(), bsks.end(), preslice.getBindingKey()); if (locate == bsks.end()) { bsks.emplace_back(preslice.getBindingKey()); } else if (locate->enabled == false) { @@ -604,7 +604,7 @@ bool registerCache(T& preslice, Cache&, Cache& bsksU) return true; } } - auto locate = std::find_if(bsksU.begin(), bsksU.end(), [&](auto const& entry) { return (entry.binding == preslice.bindingKey.binding) && (entry.key == preslice.bindingKey.key); }); + auto locate = std::find(bsksU.begin(), bsksU.end(), preslice.getBindingKey()); if (locate == bsksU.end()) { bsksU.emplace_back(preslice.getBindingKey()); } else if (locate->enabled == false) { diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index 53f6bc0f862d6..c50b5358990de 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -75,11 +75,11 @@ struct AnalysisDataProcessorBuilder { auto key = std::string{"fIndex"} + o2::framework::cutString(soa::getLabelFromType>()); ([&bk, &bku, &key, enabled]() mutable { if constexpr (soa::relatedByIndex, std::decay_t>()) { - auto binding = soa::getLabelFromTypeForKey>(key); + Entry e{soa::getLabelFromTypeForKey>(key), soa::getMatcherFromTypeForKey>(key), key, enabled}; if constexpr (o2::soa::is_smallgroups>) { - framework::updatePairList(bku, binding, key, enabled); + framework::updatePairList(bku, e); } else { - framework::updatePairList(bk, binding, key, enabled); + framework::updatePairList(bk, e); } } }(), @@ -214,7 +214,7 @@ struct AnalysisDataProcessorBuilder { template static auto extractTableFromRecord(InputRecord& record) { - auto table = record.get(o2::aod::label())->asArrowTable(); + auto table = record.get(o2::aod::matcher())->asArrowTable(); if (table->num_rows() == 0) { table = makeEmptyTable(); } diff --git a/Framework/Core/include/Framework/ArrowTableSlicingCache.h b/Framework/Core/include/Framework/ArrowTableSlicingCache.h index a6117ec3e01bc..073eadc22d72c 100644 --- a/Framework/Core/include/Framework/ArrowTableSlicingCache.h +++ b/Framework/Core/include/Framework/ArrowTableSlicingCache.h @@ -12,6 +12,7 @@ #ifndef ARROWTABLESLICINGCACHE_H #define ARROWTABLESLICINGCACHE_H +#include "Framework/ConcreteDataMatcher.h" #include "Framework/ServiceHandle.h" #include #include @@ -36,20 +37,28 @@ struct SliceInfoUnsortedPtr { struct Entry { std::string binding; + ConcreteDataMatcher matcher; std::string key; bool enabled; - Entry(std::string b, std::string k, bool e = true) + Entry(std::string b, ConcreteDataMatcher m, std::string k, bool e = true) : binding{b}, + matcher{m}, key{k}, enabled{e} { } + + friend bool operator==(Entry const& lhs, Entry const& rhs) + { + return (lhs.matcher == rhs.matcher) && + (lhs.key == rhs.key); + } }; using Cache = std::vector; -void updatePairList(Cache& list, std::string const& binding, std::string const& key, bool enabled); +void updatePairList(Cache& list, Entry& entry); struct ArrowTableSlicingCacheDef { constexpr static ServiceKind service_kind = ServiceKind::Global; diff --git a/Framework/Core/include/Framework/ConcreteDataMatcher.h b/Framework/Core/include/Framework/ConcreteDataMatcher.h index 247e3cd6ed8b9..bfbd2a05a8709 100644 --- a/Framework/Core/include/Framework/ConcreteDataMatcher.h +++ b/Framework/Core/include/Framework/ConcreteDataMatcher.h @@ -56,9 +56,9 @@ struct ConcreteDataMatcher { header::DataDescription description; header::DataHeader::SubSpecificationType subSpec; - ConcreteDataMatcher(header::DataOrigin origin_, - header::DataDescription description_, - header::DataHeader::SubSpecificationType subSpec_) + constexpr ConcreteDataMatcher(header::DataOrigin origin_, + header::DataDescription description_, + header::DataHeader::SubSpecificationType subSpec_) : origin(origin_), description(description_), subSpec(subSpec_) diff --git a/Framework/Core/include/Framework/DataSpecUtils.h b/Framework/Core/include/Framework/DataSpecUtils.h index 588aa30da7e08..fe322334a8edb 100644 --- a/Framework/Core/include/Framework/DataSpecUtils.h +++ b/Framework/Core/include/Framework/DataSpecUtils.h @@ -127,6 +127,9 @@ struct DataSpecUtils { /// unique way a description should be done, so we keep this outside. static std::string describe(OutputSpec const& spec); + /// Describes a ConcreteDataMatcher + static std::string describe(ConcreteDataMatcher const& matcher); + /// Provide a unique label for the input spec. Again this is outside because there /// is no standard way of doing it, so better not to pollute the API. static std::string label(InputSpec const& spec); @@ -211,6 +214,9 @@ struct DataSpecUtils { /// Create an InputSpec from metadata string static InputSpec fromMetadataString(std::string s); + /// Create a concrete data matcher from serialized string + static ConcreteDataMatcher fromString(std::string s); + /// Get the origin, if available static std::optional getOptionalOrigin(InputSpec const& spec); diff --git a/Framework/Core/include/Framework/DataSpecViews.h b/Framework/Core/include/Framework/DataSpecViews.h index 162a12419594e..b38866d8aa6fd 100644 --- a/Framework/Core/include/Framework/DataSpecViews.h +++ b/Framework/Core/include/Framework/DataSpecViews.h @@ -43,6 +43,13 @@ static auto filter_string_params_with(std::string match) }); } +static auto filter_string_params_starts_with(std::string match) +{ + return std::views::filter([match](auto const& param) { + return (param.type == VariantType::String) && (param.name.starts_with(match)); + }); +} + static auto input_to_output_specs() { return std::views::transform([](auto const& input) { diff --git a/Framework/Core/include/Framework/GroupSlicer.h b/Framework/Core/include/Framework/GroupSlicer.h index 4cfbb8c440fd3..596e68d8cdd4c 100644 --- a/Framework/Core/include/Framework/GroupSlicer.h +++ b/Framework/Core/include/Framework/GroupSlicer.h @@ -55,7 +55,7 @@ struct GroupSlicer { { constexpr auto index = framework::has_type_at_v>(associated_pack_t{}); auto binding = o2::soa::getLabelFromTypeForKey>(mIndexColumnName); - auto bk = Entry(binding, mIndexColumnName); + auto bk = Entry(binding, o2::soa::getMatcherFromTypeForKey>(mIndexColumnName), mIndexColumnName); if constexpr (!o2::soa::is_smallgroups>) { if (table.size() == 0) { return; diff --git a/Framework/Core/include/Framework/InputRecord.h b/Framework/Core/include/Framework/InputRecord.h index 0c9f36d00c634..96963f88524be 100644 --- a/Framework/Core/include/Framework/InputRecord.h +++ b/Framework/Core/include/Framework/InputRecord.h @@ -189,6 +189,7 @@ class InputRecord }; int getPos(const char* name) const; + int getPos(ConcreteDataMatcher matcher) const; [[nodiscard]] static InputPos getPos(std::vector const& routes, ConcreteDataMatcher matcher); [[nodiscard]] static DataRef getByPos(std::vector const& routes, InputSpan const& span, int pos, int part = 0); @@ -511,6 +512,27 @@ class InputRecord return cache.idToMetadata[id]; } + template + requires(std::same_as) + decltype(auto) get(ConcreteDataMatcher matcher, int part = 0) + { + auto pos = getPos(matcher); + if (pos < 0) { + auto msg = describeAvailableInputs(); + throw runtime_error_f("InputRecord::get: no input with binding %s found. %s", DataSpecUtils::describe(matcher).c_str(), msg.c_str()); + } + return getByPos(pos, part); + } + + template + requires(std::same_as) + decltype(auto) get(ConcreteDataMatcher matcher, int part = 0) + { + auto ref = get(matcher, part); + auto data = reinterpret_cast(ref.payload); + return std::make_unique(data, DataRefUtils::getPayloadSize(ref)); + } + /// Helper method to be used to check if a given part of the InputRecord is present. [[nodiscard]] bool isValid(std::string const& s) const { diff --git a/Framework/Core/src/AnalysisHelpers.cxx b/Framework/Core/src/AnalysisHelpers.cxx index b8e0348d5df9c..f2ecb2d68ce28 100644 --- a/Framework/Core/src/AnalysisHelpers.cxx +++ b/Framework/Core/src/AnalysisHelpers.cxx @@ -185,18 +185,18 @@ std::string serializeIndexRecords(std::vector& irs) return osm.str(); } -std::vector> extractSources(ProcessingContext& pc, std::vector const& labels) +std::vector> extractSources(ProcessingContext& pc, std::vector const& matchers) { std::vector> tables; - for (auto const& label : labels) { - tables.emplace_back(pc.inputs().get(label.c_str())->asArrowTable()); + for (auto const& matcher : matchers) { + tables.emplace_back(pc.inputs().get(matcher)->asArrowTable()); } return tables; } std::shared_ptr Spawner::materialize(ProcessingContext& pc) const { - auto tables = extractSources(pc, labels); + auto tables = extractSources(pc, matchers); auto fullTable = soa::ArrowHelpers::joinTables(std::move(tables), std::span{labels.begin(), labels.size()}); if (fullTable->num_rows() == 0) { return arrow::Table::MakeEmpty(schema).ValueOrDie(); @@ -212,7 +212,7 @@ std::shared_ptr Builder::materialize(ProcessingContext& pc) builders->reserve(records.size()); } std::shared_ptr result; - auto tables = extractSources(pc, labels); + auto tables = extractSources(pc, matchers); result = o2::soa::IndexBuilder::materialize(*builders.get(), std::move(tables), records, outputSchema, exclusive); return result; } diff --git a/Framework/Core/src/ArrowSupport.cxx b/Framework/Core/src/ArrowSupport.cxx index c403d983325dc..95e763343671a 100644 --- a/Framework/Core/src/ArrowSupport.cxx +++ b/Framework/Core/src/ArrowSupport.cxx @@ -753,7 +753,7 @@ o2::framework::ServiceSpec ArrowSupport::arrowTableSlicingCacheSpec() auto& caches = service->bindingsKeys; for (auto i = 0u; i < caches.size(); ++i) { if (caches[i].enabled && pc.inputs().getPos(caches[i].binding.c_str()) >= 0) { - auto status = service->updateCacheEntry(i, pc.inputs().get(caches[i].binding.c_str())->asArrowTable()); + auto status = service->updateCacheEntry(i, pc.inputs().get(caches[i].matcher)->asArrowTable()); if (!status.ok()) { throw runtime_error_f("Failed to update slice cache for %s/%s", caches[i].binding.c_str(), caches[i].key.c_str()); } @@ -762,7 +762,7 @@ o2::framework::ServiceSpec ArrowSupport::arrowTableSlicingCacheSpec() auto& unsortedCaches = service->bindingsKeysUnsorted; for (auto i = 0u; i < unsortedCaches.size(); ++i) { if (unsortedCaches[i].enabled && pc.inputs().getPos(unsortedCaches[i].binding.c_str()) >= 0) { - auto status = service->updateCacheEntryUnsorted(i, pc.inputs().get(unsortedCaches[i].binding.c_str())->asArrowTable()); + auto status = service->updateCacheEntryUnsorted(i, pc.inputs().get(unsortedCaches[i].matcher)->asArrowTable()); if (!status.ok()) { throw runtime_error_f("failed to update slice cache (unsorted) for %s/%s", unsortedCaches[i].binding.c_str(), unsortedCaches[i].key.c_str()); } diff --git a/Framework/Core/src/ArrowTableSlicingCache.cxx b/Framework/Core/src/ArrowTableSlicingCache.cxx index 75b4bbfac701d..634c51f71f5a6 100644 --- a/Framework/Core/src/ArrowTableSlicingCache.cxx +++ b/Framework/Core/src/ArrowTableSlicingCache.cxx @@ -37,12 +37,12 @@ std::shared_ptr GetColumnByNameCI(std::shared_ptrenabled && enabled) { + list.emplace_back(entry); + } else if (!locate->enabled && entry.enabled) { locate->enabled = true; } } @@ -110,7 +110,7 @@ arrow::Status ArrowTableSlicingCache::updateCacheEntry(int pos, std::shared_ptr< if (table->num_rows() == 0) { return arrow::Status::OK(); } - auto& [b, k, e] = bindingsKeys[pos]; + auto& [b, m, k, e] = bindingsKeys[pos]; if (!e) { throw runtime_error_f("Disabled cache %s/%s update requested", b.c_str(), k.c_str()); } @@ -169,7 +169,7 @@ arrow::Status ArrowTableSlicingCache::updateCacheEntryUnsorted(int pos, const st if (table->num_rows() == 0) { return arrow::Status::OK(); } - auto& [b, k, e] = bindingsKeysUnsorted[pos]; + auto& [b, m, k, e] = bindingsKeysUnsorted[pos]; if (!e) { throw runtime_error_f("Disabled unsorted cache %s/%s update requested", b.c_str(), k.c_str()); } @@ -210,7 +210,7 @@ std::pair ArrowTableSlicingCache::getCachePos(const Entry& bindingKey int ArrowTableSlicingCache::getCachePosSortedFor(Entry const& bindingKey) const { - auto locate = std::find_if(bindingsKeys.begin(), bindingsKeys.end(), [&](Entry const& bk) { return (bindingKey.binding == bk.binding) && (bindingKey.key == bk.key); }); + auto locate = std::find(bindingsKeys.begin(), bindingsKeys.end(), bindingKey); if (locate != bindingsKeys.end()) { return std::distance(bindingsKeys.begin(), locate); } @@ -219,7 +219,7 @@ int ArrowTableSlicingCache::getCachePosSortedFor(Entry const& bindingKey) const int ArrowTableSlicingCache::getCachePosUnsortedFor(Entry const& bindingKey) const { - auto locate_unsorted = std::find_if(bindingsKeysUnsorted.begin(), bindingsKeysUnsorted.end(), [&](Entry const& bk) { return (bindingKey.binding == bk.binding) && (bindingKey.key == bk.key); }); + auto locate_unsorted = std::find(bindingsKeysUnsorted.begin(), bindingsKeysUnsorted.end(), bindingKey); if (locate_unsorted != bindingsKeysUnsorted.end()) { return std::distance(bindingsKeysUnsorted.begin(), locate_unsorted); } @@ -269,7 +269,10 @@ SliceInfoUnsortedPtr ArrowTableSlicingCache::getCacheUnsortedForPos(int pos) con void ArrowTableSlicingCache::validateOrder(Entry const& bindingKey, const std::shared_ptr& input) { - auto const& [target, key, enabled] = bindingKey; + auto const& [target, matcher, key, enabled] = bindingKey; + if (!enabled) { + return; + } auto column = o2::framework::GetColumnByNameCI(input, key); auto array0 = static_cast>(column->chunk(0)->data()); int32_t prev = 0; diff --git a/Framework/Core/src/DataSpecUtils.cxx b/Framework/Core/src/DataSpecUtils.cxx index 48f5e6abcad5b..bc1fcd180ed76 100644 --- a/Framework/Core/src/DataSpecUtils.cxx +++ b/Framework/Core/src/DataSpecUtils.cxx @@ -89,6 +89,11 @@ std::string DataSpecUtils::describe(OutputSpec const& spec) spec.matcher); } +std::string DataSpecUtils::describe(ConcreteDataMatcher const& matcher) +{ + return join(matcher, "/"); +} + template size_t DataSpecUtils::describe(char* buffer, size_t size, T const& spec) { @@ -664,16 +669,39 @@ InputSpec DataSpecUtils::fromMetadataString(std::string s) if (std::distance(words, std::sregex_iterator()) != 4) { throw runtime_error_f("Malformed input spec metadata: %s", s.c_str()); } - std::vector data; + std::array data; + auto pos = 0; for (auto i = words; i != std::sregex_iterator(); ++i) { - data.emplace_back(i->str()); + data[pos] = i->str(); + ++pos; } char origin[4]; char description[16]; std::memcpy(&origin, data[1].c_str(), 4); std::memcpy(&description, data[2].c_str(), 16); auto version = static_cast(std::atoi(data[3].c_str())); - return InputSpec{data[0], header::DataOrigin{origin}, header::DataDescription{description}, version, Lifetime::Timeframe}; + return {data[0], header::DataOrigin{origin}, header::DataDescription{description}, version, Lifetime::Timeframe}; +} + +ConcreteDataMatcher DataSpecUtils::fromString(std::string s) +{ + std::regex word_regex("(\\w+)"); + auto words = std::sregex_iterator(s.begin(), s.end(), word_regex); + if (std::distance(words, std::sregex_iterator()) != 3) { + throw runtime_error_f("Malformed serialized matcher: %s", s.c_str()); + } + std::array data; + auto pos = 0; + for (auto i = words; i != std::sregex_iterator(); ++i) { + data[pos] = i->str(); + ++pos; + } + char origin[4]; + char description[16]; + std::memcpy(&origin, data[0].c_str(), 4); + std::memcpy(&description, data[1].c_str(), 16); + auto version = static_cast(std::atoi(data[2].c_str())); + return {header::DataOrigin{origin}, header::DataDescription{description}, version}; } std::optional DataSpecUtils::getOptionalOrigin(InputSpec const& spec) diff --git a/Framework/Core/src/IndexJSONHelpers.cxx b/Framework/Core/src/IndexJSONHelpers.cxx index 19ae94a4bcd4c..a5c6c70579599 100644 --- a/Framework/Core/src/IndexJSONHelpers.cxx +++ b/Framework/Core/src/IndexJSONHelpers.cxx @@ -41,6 +41,7 @@ struct IndexRecordsReader : public rapidjson::BaseReaderHandler& w, std::vector const& schema, ConcreteDataMatcher concrete) { size_t inputIndex = 0; diff --git a/Framework/Core/test/benchmark_EventMixing.cxx b/Framework/Core/test/benchmark_EventMixing.cxx index 99a7d0d4b1cb9..0e7e6839ee35e 100644 --- a/Framework/Core/test/benchmark_EventMixing.cxx +++ b/Framework/Core/test/benchmark_EventMixing.cxx @@ -78,7 +78,8 @@ static void BM_EventMixingTraditional(benchmark::State& state) auto tableTrack = trackBuilder.finalize(); o2::aod::StoredTracks tracks{tableTrack}; - ArrowTableSlicingCache atscache({{getLabelFromType(), "fIndex" + cutString(getLabelFromType())}}); + std::string key = "fIndex" + cutString(getLabelFromType()); + ArrowTableSlicingCache atscache({{getLabelFromType(), getMatcherFromTypeForKey(key), key}}); auto s = atscache.updateCacheEntry(0, tableTrack); SliceCache cache{&atscache}; @@ -171,7 +172,8 @@ static void BM_EventMixingCombinations(benchmark::State& state) int64_t count = 0; int64_t colCount = 0; - ArrowTableSlicingCache atscache{{{getLabelFromType(), "fIndex" + getLabelFromType()}}}; + std::string key = "fIndex" + getLabelFromType(); + ArrowTableSlicingCache atscache{{{getLabelFromType(), getMatcherFromTypeForKey(key), key}}}; auto s = atscache.updateCacheEntry(0, tableTrack); SliceCache cache{&atscache}; diff --git a/Framework/Core/test/test_ASoA.cxx b/Framework/Core/test/test_ASoA.cxx index 80519aebc9ee7..117dddff4c548 100644 --- a/Framework/Core/test/test_ASoA.cxx +++ b/Framework/Core/test/test_ASoA.cxx @@ -1187,7 +1187,8 @@ TEST_CASE("TestSliceByCached") auto refs = w.finalize(); o2::aod::References r{refs}; - ArrowTableSlicingCache atscache({{o2::soa::getLabelFromType(), "fIndex" + o2::framework::cutString(o2::soa::getLabelFromType())}}); + std::string key = "fIndex" + o2::framework::cutString(o2::soa::getLabelFromType()); + ArrowTableSlicingCache atscache({{o2::soa::getLabelFromType(), o2::soa::getMatcherFromTypeForKey(key), key}}); auto s = atscache.updateCacheEntry(0, refs); SliceCache cache{&atscache}; @@ -1238,7 +1239,7 @@ TEST_CASE("TestSliceByCachedMismatched") J rr{{refs, refs2}}; auto key = "fIndex" + o2::framework::cutString(o2::soa::getLabelFromType()) + "_alt"; - ArrowTableSlicingCache atscache({{o2::soa::getLabelFromTypeForKey(key), key}}); + ArrowTableSlicingCache atscache({{o2::soa::getLabelFromTypeForKey(key), o2::soa::getMatcherFromTypeForKey(key), key}}); auto s = atscache.updateCacheEntry(0, refs2); SliceCache cache{&atscache}; diff --git a/Framework/Core/test/test_GroupSlicer.cxx b/Framework/Core/test/test_GroupSlicer.cxx index 2f21d7dd17975..71360f736c3fb 100644 --- a/Framework/Core/test/test_GroupSlicer.cxx +++ b/Framework/Core/test/test_GroupSlicer.cxx @@ -117,7 +117,8 @@ TEST_CASE("GroupSlicerOneAssociated") REQUIRE(t.size() == 10 * 20); auto tt = std::make_tuple(t); - ArrowTableSlicingCache slices({{soa::getLabelFromType(), "fIndex" + o2::framework::cutString(soa::getLabelFromType())}}); + std::string key = "fIndex" + o2::framework::cutString(soa::getLabelFromType()); + ArrowTableSlicingCache slices({{soa::getLabelFromType(), soa::getMatcherFromTypeForKey(key), key}}); auto s = slices.updateCacheEntry(0, trkTable); o2::framework::GroupSlicer g(e, tt, slices); @@ -191,9 +192,9 @@ TEST_CASE("GroupSlicerSeveralAssociated") auto tt = std::make_tuple(tx, ty, tz, tu); auto key = "fIndex" + o2::framework::cutString(soa::getLabelFromType()); - ArrowTableSlicingCache slices({{soa::getLabelFromType(), key}, - {soa::getLabelFromType(), key}, - {soa::getLabelFromType(), key}}); + ArrowTableSlicingCache slices({{soa::getLabelFromType(), soa::getMatcherFromTypeForKey(key), key}, + {soa::getLabelFromType(), soa::getMatcherFromTypeForKey(key), key}, + {soa::getLabelFromType(), soa::getMatcherFromTypeForKey(key), key}}); auto s = slices.updateCacheEntry(0, {trkTableX}); s = slices.updateCacheEntry(1, {trkTableY}); s = slices.updateCacheEntry(2, {trkTableZ}); @@ -256,7 +257,8 @@ TEST_CASE("GroupSlicerMismatchedGroups") REQUIRE(t.size() == 10 * (20 - 5)); auto tt = std::make_tuple(t); - ArrowTableSlicingCache slices({{soa::getLabelFromType(), "fIndex" + o2::framework::cutString(soa::getLabelFromType())}}); + std::string key = "fIndex" + o2::framework::cutString(soa::getLabelFromType()); + ArrowTableSlicingCache slices({{soa::getLabelFromType(), soa::getMatcherFromTypeForKey(key), key}}); auto s = slices.updateCacheEntry(0, trkTable); o2::framework::GroupSlicer g(e, tt, slices); @@ -312,7 +314,8 @@ TEST_CASE("GroupSlicerMismatchedUnassignedGroups") REQUIRE(t.size() == (30 + 10 * (20 - 5))); auto tt = std::make_tuple(t); - ArrowTableSlicingCache slices({{soa::getLabelFromType(), "fIndex" + o2::framework::cutString(soa::getLabelFromType())}}); + std::string key = "fIndex" + o2::framework::cutString(soa::getLabelFromType()); + ArrowTableSlicingCache slices({{soa::getLabelFromType(), soa::getMatcherFromTypeForKey(key), key}}); auto s = slices.updateCacheEntry(0, trkTable); o2::framework::GroupSlicer g(e, tt, slices); @@ -362,7 +365,8 @@ TEST_CASE("GroupSlicerMismatchedFilteredGroups") REQUIRE(t.size() == 10 * (20 - 4)); auto tt = std::make_tuple(t); - ArrowTableSlicingCache slices({{soa::getLabelFromType(), "fIndex" + o2::framework::cutString(soa::getLabelFromType())}}); + std::string key = "fIndex" + o2::framework::cutString(soa::getLabelFromType()); + ArrowTableSlicingCache slices({{soa::getLabelFromType(), soa::getMatcherFromTypeForKey(key), key}}); auto s = slices.updateCacheEntry(0, trkTable); o2::framework::GroupSlicer g(e, tt, slices); @@ -423,7 +427,8 @@ TEST_CASE("GroupSlicerMismatchedUnsortedFilteredGroups") REQUIRE(t.size() == 10 * (20 - 4)); auto tt = std::make_tuple(t); - ArrowTableSlicingCache slices({}, {{soa::getLabelFromType(), "fIndex" + o2::framework::cutString(soa::getLabelFromType())}}); + std::string key = "fIndex" + o2::framework::cutString(soa::getLabelFromType()); + ArrowTableSlicingCache slices({}, {{soa::getLabelFromType(), soa::getMatcherFromTypeForKey(key), key}}); auto s = slices.updateCacheEntryUnsorted(0, trkTable); o2::framework::GroupSlicer g(e, tt, slices); @@ -547,8 +552,9 @@ TEST_CASE("GroupSlicerMismatchedUnsortedFilteredGroupsWithSelfIndex") } FilteredParts fp{{partsTable}, rows}; auto associatedTuple = std::make_tuple(fp, t); - ArrowTableSlicingCache slices({{soa::getLabelFromType(), "fIndex" + o2::framework::cutString(soa::getLabelFromType())}, - {soa::getLabelFromType(), "fIndex" + o2::framework::cutString(soa::getLabelFromType())}}); + std::string key = "fIndex" + o2::framework::cutString(soa::getLabelFromType()); + ArrowTableSlicingCache slices({{soa::getLabelFromType(), soa::getMatcherFromTypeForKey(key), key}, + {soa::getLabelFromType(), soa::getMatcherFromTypeForKey(key), key}}); auto s0 = slices.updateCacheEntry(0, partsTable); auto s1 = slices.updateCacheEntry(1, thingsTable); o2::framework::GroupSlicer g(e, associatedTuple, slices); @@ -607,7 +613,8 @@ TEST_CASE("EmptySliceables") REQUIRE(t.size() == 0); auto tt = std::make_tuple(t); - ArrowTableSlicingCache slices({{soa::getLabelFromType(), "fIndex" + o2::framework::cutString(soa::getLabelFromType())}}); + std::string key = "fIndex" + o2::framework::cutString(soa::getLabelFromType()); + ArrowTableSlicingCache slices({{soa::getLabelFromType(), soa::getMatcherFromTypeForKey(key), key}}); auto s = slices.updateCacheEntry(0, trkTable); o2::framework::GroupSlicer g(e, tt, slices); @@ -679,7 +686,7 @@ TEST_CASE("ArrowDirectSlicing") std::vector slices; std::vector offsts; - auto bk = Entry(soa::getLabelFromType(), "fID"); + auto bk = Entry(soa::getLabelFromType(), soa::getMatcherFromTypeForKey("fID"), "fID"); ArrowTableSlicingCache cache({bk}); auto s = cache.updateCacheEntry(0, {evtTable}); auto lcache = cache.getCacheFor(bk); @@ -737,7 +744,7 @@ TEST_CASE("TestSlicingException") } auto evtTable = builderE.finalize(); - auto bk = Entry(soa::getLabelFromType(), "fID"); + auto bk = Entry(soa::getLabelFromType(), soa::getMatcherFromTypeForKey("fID"), "fID"); ArrowTableSlicingCache cache({bk}); try { diff --git a/Framework/TestWorkflows/CMakeLists.txt b/Framework/TestWorkflows/CMakeLists.txt index f5d18183c3705..d2b98419043bf 100644 --- a/Framework/TestWorkflows/CMakeLists.txt +++ b/Framework/TestWorkflows/CMakeLists.txt @@ -46,6 +46,10 @@ o2_add_dpl_workflow(analysis-ccdb PUBLIC_LINK_LIBRARIES O2::DataFormatsTOF COMPONENT_NAME TestWorkflows) +o2_add_dpl_workflow(analysis-emb + SOURCES src/o2TestMultisource.cxx + COMPONENT_NAME TestWorkflows) + o2_add_dpl_workflow(two-timers SOURCES src/o2TwoTimers.cxx COMPONENT_NAME TestWorkflows) diff --git a/Framework/TestWorkflows/src/o2TestHistograms.cxx b/Framework/TestWorkflows/src/o2TestHistograms.cxx index 640a165fb91ff..9c2cba35b9156 100644 --- a/Framework/TestWorkflows/src/o2TestHistograms.cxx +++ b/Framework/TestWorkflows/src/o2TestHistograms.cxx @@ -16,8 +16,6 @@ #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" #include -#include -#include using namespace o2; using namespace o2::framework; @@ -72,7 +70,7 @@ struct EtaAndClsHistogramsSimple { } } - void process(soa::Filtered const& tracks, aod::FT0s const&, aod::StoredTracksFrom> const& ortherTracks) + void process(soa::Filtered const& tracks, aod::FT0s const&) { LOGP(info, "Invoking the simple one"); for (auto& track : tracks) { @@ -110,7 +108,7 @@ struct EtaAndClsHistogramsIUSimple { } } - void process(soa::Filtered const& tracks, aod::FT0s const&, aod::TracksIUFrom> const& otherTracks) + void process(soa::Filtered const& tracks, aod::FT0s const&) { LOGP(info, "Invoking the simple one IU"); for (auto& track : tracks) { diff --git a/Framework/TestWorkflows/src/o2TestMultisource.cxx b/Framework/TestWorkflows/src/o2TestMultisource.cxx new file mode 100644 index 0000000000000..00bd9ba5093bd --- /dev/null +++ b/Framework/TestWorkflows/src/o2TestMultisource.cxx @@ -0,0 +1,47 @@ +// Copyright 2019-2026 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. +/// +/// \brief Tests that the same tables from different origins are routed correctly. +/// Requires two input files, .root and _EMB.root, that contain +/// same number of DFs with the same names. +/// \author +/// \since + +#include "Framework/runDataProcessing.h" +#include "Framework/AnalysisTask.h" + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +namespace o2::aod +{ +O2ORIGIN("EMB"); +template +using BCsFrom = BCs_001From; +using TracksPlus = soa::Join; +template +using TracksPlusFrom = soa::Join, StoredTracksExtra_002From>; +} // namespace o2::aod + +struct TestEmbeddingSubscription { + void process(aod::BCs const& bcs, aod::BCsFrom> const& bcse, + aod::TracksPlus const& tracks, aod::TracksPlusFrom> const& trackse) + { + LOGP(info, "BCs from run {} and {}", bcs.begin().runNumber(), bcse.begin().runNumber()); + LOGP(info, "Joined tracks: {} and {}", tracks.size(), trackse.size()); + } +}; + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + return {adaptAnalysisTask(cfgc)}; +} From b5dfe5011ab8a7399ee9c41dba66175feee68033 Mon Sep 17 00:00:00 2001 From: ehellbar Date: Thu, 15 Jan 2026 19:50:34 +0100 Subject: [PATCH 086/234] start_tmux.sh: create ED directory to avoid filesystem errors during o2-eve-export-workflow (#14961) --- prodtests/full-system-test/start_tmux.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/prodtests/full-system-test/start_tmux.sh b/prodtests/full-system-test/start_tmux.sh index 22b658856803a..fb69cc1e6baec 100755 --- a/prodtests/full-system-test/start_tmux.sh +++ b/prodtests/full-system-test/start_tmux.sh @@ -91,6 +91,7 @@ export DATADIST_NEW_DPL_CHAN=1 [[ -z $GEN_TOPO_MYDIR ]] && GEN_TOPO_MYDIR="$(dirname $(realpath $0))" source $GEN_TOPO_MYDIR/setenv.sh || { echo "setenv.sh failed" 1>&2 && exit 1; } +mkdir -p $EDJSONS_DIR # create event display directory to avoid filesystem error messages workflow_has_parameter QC && export QC_REDIRECT_MERGER_TO_LOCALHOST=1 From 0a8627db853ed9bf9537a2792e2e2c5afa4e3c94 Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Fri, 16 Jan 2026 15:00:07 +0100 Subject: [PATCH 087/234] Switch option from external to hybrid (#14951) --- .../include/Generators/GeneratorHybridParam.h | 7 +-- Generators/src/GeneratorFactory.cxx | 6 +++ .../GeneratorHyperloopHybrid.ini | 3 ++ .../GeneratorHyperloopHybridCocktail.ini | 3 ++ run/SimExamples/ExternalToHybrid/README.md | 45 ++++++++++++++++ .../ExternalToHybrid/cocktail.json | 49 +++++++++++++++++ run/SimExamples/ExternalToHybrid/rundpl.sh | 54 +++++++++++++++++++ .../ExternalToHybrid/sequential.json | 35 ++++++++++++ 8 files changed, 199 insertions(+), 3 deletions(-) create mode 100644 run/SimExamples/ExternalToHybrid/GeneratorHyperloopHybrid.ini create mode 100644 run/SimExamples/ExternalToHybrid/GeneratorHyperloopHybridCocktail.ini create mode 100644 run/SimExamples/ExternalToHybrid/README.md create mode 100644 run/SimExamples/ExternalToHybrid/cocktail.json create mode 100755 run/SimExamples/ExternalToHybrid/rundpl.sh create mode 100644 run/SimExamples/ExternalToHybrid/sequential.json diff --git a/Generators/include/Generators/GeneratorHybridParam.h b/Generators/include/Generators/GeneratorHybridParam.h index c05b70dcb40ba..acdf87bba2d0a 100644 --- a/Generators/include/Generators/GeneratorHybridParam.h +++ b/Generators/include/Generators/GeneratorHybridParam.h @@ -29,9 +29,10 @@ namespace eventgen **/ struct GeneratorHybridParam : public o2::conf::ConfigurableParamHelper { - std::string configFile = ""; // JSON configuration file for the generators - bool randomize = false; // randomize the order of the generators, if not generator using fractions - int num_workers = 1; // number of threads available for asyn/parallel event generation + std::string configFile = ""; // JSON configuration file for the generators + bool randomize = false; // randomize the order of the generators, if not generator using fractions + int num_workers = 1; // number of threads available for asyn/parallel event generation + bool switchExtToHybrid = false; // force external generator to be executed as hybrid mode, useful for Hyperloop MCGEN O2ParamDef(GeneratorHybridParam, "GeneratorHybrid"); }; diff --git a/Generators/src/GeneratorFactory.cxx b/Generators/src/GeneratorFactory.cxx index d04e785402915..1cc2659460a4b 100644 --- a/Generators/src/GeneratorFactory.cxx +++ b/Generators/src/GeneratorFactory.cxx @@ -93,6 +93,12 @@ void GeneratorFactory::setPrimaryGenerator(o2::conf::SimConfig const& conf, Fair o2::O2DatabasePDG::addALICEParticles(TDatabasePDG::Instance()); auto genconfig = conf.getGenerator(); +#if defined(GENERATORS_WITH_PYTHIA8) && defined(GENERATORS_WITH_HEPMC3) + if (GeneratorHybridParam::Instance().switchExtToHybrid && (genconfig.compare("external") == 0 || genconfig.compare("extgen") == 0)) { + LOG(info) << "Switching external generator to hybrid mode"; + genconfig = "hybrid"; + } +#endif LOG(info) << "** Generator to use: '" << genconfig << "'"; if (genconfig.compare("boxgen") == 0) { // a simple "box" generator configurable via BoxGunparam diff --git a/run/SimExamples/ExternalToHybrid/GeneratorHyperloopHybrid.ini b/run/SimExamples/ExternalToHybrid/GeneratorHyperloopHybrid.ini new file mode 100644 index 0000000000000..0105349ea4d42 --- /dev/null +++ b/run/SimExamples/ExternalToHybrid/GeneratorHyperloopHybrid.ini @@ -0,0 +1,3 @@ +[GeneratorHybrid] +configFile = ${O2_ROOT}/examples/ExternalToHybrid/sequential.json +switchExtToHybrid = true \ No newline at end of file diff --git a/run/SimExamples/ExternalToHybrid/GeneratorHyperloopHybridCocktail.ini b/run/SimExamples/ExternalToHybrid/GeneratorHyperloopHybridCocktail.ini new file mode 100644 index 0000000000000..11728f970d688 --- /dev/null +++ b/run/SimExamples/ExternalToHybrid/GeneratorHyperloopHybridCocktail.ini @@ -0,0 +1,3 @@ +[GeneratorHybrid] +configFile = ${O2_ROOT}/examples/ExternalToHybrid/cocktail.json +switchExtToHybrid = true diff --git a/run/SimExamples/ExternalToHybrid/README.md b/run/SimExamples/ExternalToHybrid/README.md new file mode 100644 index 0000000000000..28292cdf9277a --- /dev/null +++ b/run/SimExamples/ExternalToHybrid/README.md @@ -0,0 +1,45 @@ + + +This example demonstrates how to bypass the Hyperloop limitations when using external generators by switching the configuration to hybrid mode, using the new `GeneratorHybrid.switchExtToHybrid` parameter (set to false by default). + +This solution works only with updated O2sim versions containing the `switchExtToHybrid` option. + +# Configuration Files + +Two example configuration files are provided, each pointing to different hybrid JSON files: + +- **GeneratorHyperloopHybridCocktail.ini** → Creates a cocktail mixing two Pythia8 based generators and a boxgen instance +- **GeneratorHyperloopHybrid.ini** → Defines sequential generation of boxgen and EPOS4 events called with an external generator + +# Script Description + +## rundpl.sh + +This script demonstrates event generation using the DPL framework, launching it with the external generator in hybrid mode. + +### Available Flags + +- **-i, --ini CONFIG** → Specifies the configuration ini file (default: `GeneratorHyperloopHybridCocktail.ini`) +- **-n, --nevents EVENTS** → Sets the number of events to generate (default: 5) +- **-h, --help** → Prints usage instructions and o2-sim-dpl-eventgen help +- **--** → Passes remaining command line arguments to o2-sim-dpl-eventgen + +### Usage Examples + +Run with default settings (5 events using cocktail configuration): +```bash +./rundpl.sh +``` + +Generate 10 events using the sequential configuration: +```bash +./rundpl.sh -n 10 -i ${O2_ROOT}/examples/ExternalToHybrid/GeneratorHyperloopHybrid.ini +``` + +# Requirements + +- O2sim version with `switchExtToHybrid` support +- O2_ROOT and O2DPG_MC_CONFIG_ROOT environment variable must be loaded (possibly via O2sim directly) +- Appropriate external generator configurations (e.g., EPOS4) must be available \ No newline at end of file diff --git a/run/SimExamples/ExternalToHybrid/cocktail.json b/run/SimExamples/ExternalToHybrid/cocktail.json new file mode 100644 index 0000000000000..2e8a4c964b1c6 --- /dev/null +++ b/run/SimExamples/ExternalToHybrid/cocktail.json @@ -0,0 +1,49 @@ +{ + "generators": [ + { + "cocktail": [ + { + "name": "pythia8", + "config": { + "config": "${O2_ROOT}/share/Generators/egconfig/pythia8_inel.cfg", + "hooksFileName": "", + "hooksFuncName": "", + "includePartonEvent": false, + "particleFilter": "", + "verbose": 0 + } + }, + { + "name": "external", + "config": { + "fileName": "", + "funcName": "", + "iniFile": "${O2DPG_MC_CONFIG_ROOT}/MC/config/ALICE3/ini/pythia8_pp_13tev.ini" + } + }, + { + "name": "boxgen", + "config": { + "pdg": 443, + "number": 10, + "eta": [ + -0.8, + 0.8 + ], + "prange": [ + 0.1, + 5 + ], + "phirange": [ + 0, + 360 + ] + } + } + ] + } + ], + "fractions": [ + 1 + ] +} \ No newline at end of file diff --git a/run/SimExamples/ExternalToHybrid/rundpl.sh b/run/SimExamples/ExternalToHybrid/rundpl.sh new file mode 100755 index 0000000000000..e9bd15b239862 --- /dev/null +++ b/run/SimExamples/ExternalToHybrid/rundpl.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +# +# This is a simple example script to bypass the Hyperloop limitations in using +# external generators only, by switching the generator to the hybrid mode + +# This script works only with updated O2sim version containing the switchExtToHybrid option + +[ ! "${O2_ROOT}" ] && echo "Error: This needs O2 loaded" && exit 2 +[ ! "${O2DPG_MC_CONFIG_ROOT}" ] && echo "Error: This needs O2DPG loaded" && exit 2 + +NEV=5 +# Two example ini configurations are provided pointing to different hybrid JSON files +# One creates a cocktail based on Pythia8, while the other generates sequentially EPOS4 and boxgen events +ini="${O2_ROOT}/examples/ExternalToHybrid/GeneratorHyperloopHybridCocktail.ini" + +usage() +{ + cat </dev/stderr + exit 3 + ;; + esac + shift +done + +# Starting the dpl-eventgen simulation +o2-sim-dpl-eventgen -b --generator external --nEvents $NEV --configFile $ini \ No newline at end of file diff --git a/run/SimExamples/ExternalToHybrid/sequential.json b/run/SimExamples/ExternalToHybrid/sequential.json new file mode 100644 index 0000000000000..bfb810f745f6a --- /dev/null +++ b/run/SimExamples/ExternalToHybrid/sequential.json @@ -0,0 +1,35 @@ +{ + "generators": [ + { + "name": "boxgen", + "config": { + "pdg": 443, + "number": 10, + "eta": [ + -0.8, + 0.8 + ], + "prange": [ + 0.1, + 5 + ], + "phirange": [ + 0, + 360 + ] + } + }, + { + "name": "external", + "config": { + "fileName": "", + "funcName": "", + "iniFile": "${O2DPG_MC_CONFIG_ROOT}/MC/config/examples/ini/GeneratorEPOS4_pp13TeV.ini" + } + } + ], + "fractions": [ + 1, + 1 + ] +} \ No newline at end of file From c5c328283cc56fb8fe2d3d17912bf5e738cd02fe Mon Sep 17 00:00:00 2001 From: Andrea Sofia Triolo Date: Fri, 16 Jan 2026 16:23:38 +0100 Subject: [PATCH 088/234] ALICE3-TRK: partial fix to issue #14959 (#14965) * ALICE3-TRK: fix matrix path for cylindrical ML and OT geometries * ALICE3-TRK: setting turboStaves and staggered layouts as default for ML and OT, respectively --- .../TRK/base/include/TRKBase/GeometryTGeo.h | 4 ++++ .../TRK/base/include/TRKBase/TRKBaseParam.h | 7 +++++-- .../ALICE3/TRK/base/src/GeometryTGeo.cxx | 16 ++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h index ee6f5f33fc9fe..deec53950cd5f 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/GeometryTGeo.h @@ -15,6 +15,7 @@ #include #include #include "DetectorsCommonDataFormats/DetID.h" +#include "TRKBase/TRKBaseParam.h" namespace o2 { @@ -221,6 +222,9 @@ class GeometryTGeo : public o2::detectors::DetMatrixCache std::vector mCacheRefXMLOT; /// cache for X of ML and OT std::vector mCacheRefAlphaMLOT; /// cache for sensor ref alpha ML and OT + eLayout mLayoutML; // Type of segmentation for the middle layers + eLayout mLayoutOL; // Type of segmentation for the outer layers + private: static std::unique_ptr sInstance; }; diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h index 3f3f656c4b417..7f2f7f32b79d9 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h @@ -38,8 +38,11 @@ struct TRKBaseParam : public o2::conf::ConfigurableParamHelper { eOverallGeom overallGeom = kDefaultRadii; // Overall geometry option, to be used in Detector::buildTRKMiddleOuterLayers - eLayout layoutML = kCylinder; // Type of segmentation for the middle layers - eLayout layoutOL = kCylinder; // Type of segmentation for the outer layers + eLayout layoutML = kTurboStaves; // Type of segmentation for the middle layers + eLayout layoutOL = kStaggered; // Type of segmentation for the outer layers + + eLayout getLayoutML() const { return layoutML; } + eLayout getLayoutOL() const { return layoutOL; } O2ParamDef(TRKBaseParam, "TRKBase"); }; diff --git a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx index bfa23fe57c01a..b32c89164f18a 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx @@ -76,6 +76,11 @@ void GeometryTGeo::Build(int loadTrans) LOGP(fatal, "Geometry is not loaded"); } + mLayoutML = o2::trk::TRKBaseParam::Instance().getLayoutML(); + mLayoutOL = o2::trk::TRKBaseParam::Instance().getLayoutOL(); + + LOG(debug) << "Layout ML: " << mLayoutML << ", Layout OL: " << mLayoutOL; + mNumberOfLayersMLOT = extractNumberOfLayersMLOT(); mNumberOfPetalsVD = extractNumberOfPetalsVD(); mNumberOfActivePartsVD = extractNumberOfActivePartsVD(); @@ -398,6 +403,17 @@ TString GeometryTGeo::getMatrixPath(int index) const // TString path = "/cave_1/barrel_1/TRKV_2/TRKLayer0_1/TRKStave0_1/TRKChip0_1/TRKSensor0_1/"; /// dummy path, to be used for tests TString path = Form("/cave_1/barrel_1/%s_2/", GeometryTGeo::getTRKVolPattern()); + // handling cylindrical configuration for ML and/or OT + // needed bercause of the different numbering scheme in the geometry for the cylindrical case wrt the staggered and turbo ones + if (subDetID == 1) { + if ((layer < 4 && mLayoutML == eLayout::kCylinder) || (layer > 3 && mLayoutOL == eLayout::kCylinder)) { + stave = 1; + mod = 1; + chip = 1; + } + } + + // build the path if (subDetID == 0) { // VD if (disk >= 0) { path += Form("%s_%d_%d/", getTRKPetalAssemblyPattern(), petalcase, petalcase + 1); // PETAL_n From 8ead4583abb166786d6e76c6ca9f8fd90e595e76 Mon Sep 17 00:00:00 2001 From: tubagundem Date: Mon, 8 Dec 2025 15:58:08 +0100 Subject: [PATCH 089/234] TPC_MC_anchoring_simple: Added per region relative gas gain to simulate the change in the voltage settings of GEMs --- Detectors/TPC/base/include/TPCBase/ParameterGEM.h | 1 + .../TPC/simulation/include/TPCSimulation/GEMAmplification.h | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Detectors/TPC/base/include/TPCBase/ParameterGEM.h b/Detectors/TPC/base/include/TPCBase/ParameterGEM.h index 2d55a550764ac..cb458fbb5dafa 100644 --- a/Detectors/TPC/base/include/TPCBase/ParameterGEM.h +++ b/Detectors/TPC/base/include/TPCBase/ParameterGEM.h @@ -54,6 +54,7 @@ struct ParameterGEM : public o2::conf::ConfigurableParamHelper { float AbsoluteGain[4] = {14.f, 8.f, 53.f, 240.f}; ///< Absolute gain float CollectionEfficiency[4] = {1.f, 0.2f, 0.25f, 1.f}; ///< Collection efficiency float ExtractionEfficiency[4] = {0.65f, 0.55f, 0.12f, 0.6f}; ///< Extraction efficiency + float RelativeGainStack[4] = {1.f, 1.f, 1.f, 1.f}; ///< Relative gain of the stack per region (IROC, OROC1, OROC2, OROC3) for the EffectiveMode float TotalGainStack = 2000.f; ///< Total gain of the stack for the EffectiveMode float KappaStack = 1.205f; ///< Variable steering the energy resolution of the full stack for the EffectiveMode float EfficiencyStack = 0.528f; ///< Variable steering the single electron efficiency of the full stack for the EffectiveMode diff --git a/Detectors/TPC/simulation/include/TPCSimulation/GEMAmplification.h b/Detectors/TPC/simulation/include/TPCSimulation/GEMAmplification.h index f5c40569fee43..8dbfa21febc69 100644 --- a/Detectors/TPC/simulation/include/TPCSimulation/GEMAmplification.h +++ b/Detectors/TPC/simulation/include/TPCSimulation/GEMAmplification.h @@ -118,8 +118,10 @@ inline int GEMAmplification::getStackAmplification(const CRU& cru, const PadPos& break; } case AmplificationMode::EffectiveMode: { + const int region = static_cast(cru.gemStack()); + const float relativeGain = mGEMParam->RelativeGainStack[region]; return static_cast(static_cast(getEffectiveStackAmplification(nElectrons)) * - mGainMap->getValue(cru, pos.getRow(), pos.getPad())); + mGainMap->getValue(cru, pos.getRow(), pos.getPad()) * relativeGain); break; } } From 7cd4b7f29f7daf912f5773149f9d96d7d707a21f Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Sat, 17 Jan 2026 00:00:15 +0100 Subject: [PATCH 090/234] DPL: keep code checker happy (#14966) The code checker complains about the unique_ptr going out of scope. However this is a false positive because such unique_ptr has a custom deletion policy to mimick the behavior of an observer_ptr. In order to keep the code checker happy, we use release, so that the bare pointer is returned without any complain. Given the custom deleter, the semantic is actually the same. --- Framework/Core/include/Framework/AnalysisManagers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/Core/include/Framework/AnalysisManagers.h b/Framework/Core/include/Framework/AnalysisManagers.h index 5112e3659f4aa..fd41a079c6570 100644 --- a/Framework/Core/include/Framework/AnalysisManagers.h +++ b/Framework/Core/include/Framework/AnalysisManagers.h @@ -170,7 +170,7 @@ bool newDataframeCondition(InputRecord&, C&) template bool newDataframeCondition(InputRecord& record, C& condition) { - condition.instance = (typename C::type*)record.get(condition.path).get(); + condition.instance = (typename C::type*)record.get(condition.path).release(); return true; } From db7170bd9cd8ba0fd5622a617af7d4f78b584cb3 Mon Sep 17 00:00:00 2001 From: Andrea Sofia Triolo Date: Sat, 17 Jan 2026 01:14:20 +0100 Subject: [PATCH 091/234] ALICE3-TRK: fix the length of the layers for the kCylinder layout for ML and OT (#14967) --- .../ALICE3/TRK/simulation/src/TRKLayer.cxx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx index a24a8eea0be27..c4683f28918d0 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx @@ -50,7 +50,7 @@ TGeoVolume* TRKLayer::createSensor(std::string type) TGeoShape* sensor; if (type == "cylinder") { - sensor = new TGeoTube(mInnerRadius, mInnerRadius + mSensorThickness, mChipLength / 2); // TO BE CHECKED !!! + sensor = new TGeoTube(mInnerRadius, mInnerRadius + mSensorThickness, (constants::moduleMLOT::length * mNumberOfModules) / 2); // TO BE CHECKED !!! } else if (type == "flat") { sensor = new TGeoBBox((mChipWidth - mDeadzoneWidth) / 2, mSensorThickness / 2, mChipLength / 2); // TO BE CHECKED !!! } else { @@ -71,7 +71,7 @@ TGeoVolume* TRKLayer::createDeadzone(std::string type) TGeoShape* deadzone; if (type == "cylinder") { - deadzone = new TGeoTube(mInnerRadius, mInnerRadius + mSensorThickness, mChipLength / 2); // TO BE CHECKED !!! + deadzone = new TGeoTube(mInnerRadius, mInnerRadius + mSensorThickness, 0); // TO BE CHECKED !!! } else if (type == "flat") { deadzone = new TGeoBBox(mDeadzoneWidth / 2, mSensorThickness / 2, mChipLength / 2); // TO BE CHECKED !!! } else { @@ -92,7 +92,7 @@ TGeoVolume* TRKLayer::createMetalStack(std::string type) TGeoShape* metalStack; if (type == "cylinder") { - metalStack = new TGeoTube(mInnerRadius + mSensorThickness, mInnerRadius + mChipThickness, mChipLength / 2); // TO BE CHECKED !!! + metalStack = new TGeoTube(mInnerRadius + mSensorThickness, mInnerRadius + mChipThickness, (constants::moduleMLOT::length * mNumberOfModules) / 2); // TO BE CHECKED !!! } else if (type == "flat") { metalStack = new TGeoBBox(mChipWidth / 2, (mChipThickness - mSensorThickness) / 2, mChipLength / 2); // TO BE CHECKED !!! } else { @@ -118,7 +118,7 @@ TGeoVolume* TRKLayer::createChip(std::string type) TGeoVolume* metalVol; if (type == "cylinder") { - chip = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, mChipLength / 2); + chip = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, (constants::moduleMLOT::length * mNumberOfModules) / 2); chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); sensVol = createSensor("cylinder"); @@ -175,7 +175,7 @@ TGeoVolume* TRKLayer::createModule(std::string type) TGeoVolume* moduleVol; if (type == "cylinder") { - module = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, mChipLength / 2); + module = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, (constants::moduleMLOT::length * mNumberOfModules) / 2); moduleVol = new TGeoVolume(moduleName.c_str(), module, medAir); TGeoVolume* chipVol = createChip("cylinder"); @@ -269,7 +269,7 @@ TGeoVolume* TRKLayer::createStave(std::string type) TGeoVolume* staveVol; if (type == "cylinder") { - stave = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, mChipLength / 2); + stave = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, (constants::moduleMLOT::length * mNumberOfModules) / 2); staveVol = new TGeoVolume(staveName.c_str(), stave, medAir); TGeoVolume* moduleVol = createModule("cylinder"); @@ -341,7 +341,7 @@ void TRKLayer::createLayer(TGeoVolume* motherVolume) TGeoVolume* layerVol; if (mLayout == eLayout::kCylinder) { - layer = new TGeoTube(mInnerRadius - 0.333 * layerThickness, mInnerRadius + 0.667 * layerThickness, mChipLength / 2); + layer = new TGeoTube(mInnerRadius - 0.333 * layerThickness, mInnerRadius + 0.667 * layerThickness, (constants::moduleMLOT::length * mNumberOfModules) / 2); layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); TGeoVolume* staveVol = createStave("cylinder"); From c5f00f245e4f185f7fb761b13bdd07d7ec659df2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Jacazio?= Date: Mon, 19 Jan 2026 08:37:02 +0100 Subject: [PATCH 092/234] A3: Fix geometry building of FT3 (#14968) Added logging for material initialization and layout creation. --- .../ALICE3/FT3/simulation/src/FT3Module.cxx | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx b/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx index 87f5f27da6a38..efcad74bc2cb9 100644 --- a/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx +++ b/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -41,12 +42,12 @@ TGeoMedium* FT3Module::AluminumMed = nullptr; void FT3Module::initialize_materials() { - + LOG(debug) << "FT3Module: initialize_materials"; if (siliconMat) { return; } - TGeoManager* gGeoManager = gGeoManager; + TGeoManager* geoManager = gGeoManager; auto* itsH = new TGeoElement("FT3_H", "Hydrogen", 1, 1.00794); auto* itsC = new TGeoElement("FT3_C", "Carbon", 6, 12.0107); @@ -73,6 +74,7 @@ void FT3Module::initialize_materials() AluminumMat = new TGeoMaterial("Aluminum", 26.98, 13, 2.7); AluminumMed = new TGeoMedium("Aluminum", 5, AluminumMat); + LOG(debug) << "FT3Module: done initialize_materials"; } double calculate_y_circle(double x, double radius) @@ -83,7 +85,8 @@ double calculate_y_circle(double x, double radius) void FT3Module::create_layout(double mZ, int layerNumber, int direction, double Rin, double Rout, double overlap, const std::string& face, const std::string& layout_type, TGeoVolume* motherVolume) { - TGeoManager* gGeoManager = gGeoManager; + LOG(debug) << "FT3Module: create_layout - Layer " << layerNumber << ", Direction " << direction << ", Face " << face; + TGeoManager* geoManager = gGeoManager; FT3Module::initialize_materials(); @@ -479,13 +482,13 @@ void FT3Module::create_layout(double mZ, int layerNumber, int direction, double if (sensor_width == 2.5) { // silicon std::string sensor_name = "FT3sensor_front_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(sensor_name.c_str(), siliconMed, active_width / 2, active_height / 2, silicon_thickness / 2); + sensor = geoManager->MakeBox(sensor_name.c_str(), siliconMed, active_width / 2, active_height / 2, silicon_thickness / 2); sensor->SetLineColor(SiColor); sensor->SetFillColorAlpha(SiColor, 0.4); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(active_x_shift_sensor + x_offset, y + y_offset, mZ + z_offset - epoxy_thickness - kapton_thickness - copper_thickness - epoxy_thickness - silicon_thickness / 2)); std::string inactive_name = "FT3inactive_front_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(inactive_name.c_str(), siliconMed, (sensor_width - active_width) / 2, sensor_height / 2, silicon_thickness / 2); + sensor = geoManager->MakeBox(inactive_name.c_str(), siliconMed, (sensor_width - active_width) / 2, sensor_height / 2, silicon_thickness / 2); sensor->SetLineColor(kRed); sensor->SetFillColorAlpha(kRed, 1.0); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(x_offset + inactive_x_shift, y + y_offset, mZ + z_offset - epoxy_thickness - kapton_thickness - copper_thickness - epoxy_thickness - silicon_thickness / 2)); @@ -493,19 +496,19 @@ void FT3Module::create_layout(double mZ, int layerNumber, int direction, double } else { std::string sensor_name = "FT3sensor_front_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(sensor_name.c_str(), siliconMed, active_width / 2, sensor_height / 2, silicon_thickness / 2); + sensor = geoManager->MakeBox(sensor_name.c_str(), siliconMed, active_width / 2, sensor_height / 2, silicon_thickness / 2); sensor->SetLineColor(SiColor); sensor->SetFillColorAlpha(SiColor, 0.4); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(x_offset + x + inactive_width / 2, y + y_offset, mZ + z_offset - epoxy_thickness - kapton_thickness - copper_thickness - epoxy_thickness - silicon_thickness / 2)); std::string inactive_name_left = "FT3inactive_left_front_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(inactive_name_left.c_str(), siliconMed, inactive_width / 2, sensor_height / 2, silicon_thickness / 2); + sensor = geoManager->MakeBox(inactive_name_left.c_str(), siliconMed, inactive_width / 2, sensor_height / 2, silicon_thickness / 2); sensor->SetLineColor(kRed); sensor->SetFillColorAlpha(kRed, 1.0); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(x_offset + inactive_x_shift_left, y + y_offset, mZ + z_offset - epoxy_thickness - kapton_thickness - copper_thickness - epoxy_thickness - silicon_thickness / 2)); std::string inactive_name_right = "FT3inactive_right_front_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(inactive_name_right.c_str(), siliconMed, inactive_width / 2, sensor_height / 2, silicon_thickness / 2); + sensor = geoManager->MakeBox(inactive_name_right.c_str(), siliconMed, inactive_width / 2, sensor_height / 2, silicon_thickness / 2); sensor->SetLineColor(kRed); sensor->SetFillColorAlpha(kRed, 1.0); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(x_offset + inactive_x_shift_right, y + y_offset, mZ + z_offset - epoxy_thickness - kapton_thickness - copper_thickness - epoxy_thickness - silicon_thickness / 2)); @@ -513,21 +516,21 @@ void FT3Module::create_layout(double mZ, int layerNumber, int direction, double // silicon-to-FPC epoxy glue std::string glue_up_name = "FT3glue_up_front_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(glue_up_name.c_str(), epoxyMed, sensor_width / 2, sensor_height / 2, epoxy_thickness / 2); + sensor = geoManager->MakeBox(glue_up_name.c_str(), epoxyMed, sensor_width / 2, sensor_height / 2, epoxy_thickness / 2); sensor->SetLineColor(kBlue); sensor->SetFillColorAlpha(kBlue, 1.0); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(x_offset + active_x_shift, y + y_offset, mZ + z_offset - epoxy_thickness - kapton_thickness - copper_thickness - epoxy_thickness / 2)); if (r_squared < R_material_threshold * R_material_threshold) { std::string alu_name = "FT3aluminum_front_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(alu_name.c_str(), AluminumMed, sensor_width / 2, sensor_height / 2, copper_thickness / 2); + sensor = geoManager->MakeBox(alu_name.c_str(), AluminumMed, sensor_width / 2, sensor_height / 2, copper_thickness / 2); sensor->SetLineColor(kBlack); sensor->SetFillColorAlpha(kBlack, 0.4); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(active_x_shift + x_offset, y + y_offset, mZ + z_offset - epoxy_thickness - kapton_thickness - copper_thickness / 2)); } else { std::string copper_name = "FT3copper_front_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(copper_name.c_str(), copperMed, sensor_width / 2, sensor_height / 2, copper_thickness / 2); + sensor = geoManager->MakeBox(copper_name.c_str(), copperMed, sensor_width / 2, sensor_height / 2, copper_thickness / 2); sensor->SetLineColor(kBlack); sensor->SetFillColorAlpha(kBlack, 0.4); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(active_x_shift + x_offset, y + y_offset, mZ + z_offset - epoxy_thickness - kapton_thickness - copper_thickness / 2)); @@ -535,14 +538,14 @@ void FT3Module::create_layout(double mZ, int layerNumber, int direction, double // kapton std::string fpc_name = "FT3fpc_front_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(fpc_name.c_str(), kaptonMed, sensor_width / 2, sensor_height / 2, kapton_thickness / 2); + sensor = geoManager->MakeBox(fpc_name.c_str(), kaptonMed, sensor_width / 2, sensor_height / 2, kapton_thickness / 2); sensor->SetLineColor(kGreen); sensor->SetFillColorAlpha(kGreen, 0.4); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(active_x_shift + x_offset, y + y_offset, mZ + z_offset - epoxy_thickness - kapton_thickness / 2)); // FPC-to-support epoxy glue std::string glue_down_name = "FT3glue_down_front_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(glue_down_name.c_str(), epoxyMed, sensor_width / 2, sensor_height / 2, epoxy_thickness / 2); + sensor = geoManager->MakeBox(glue_down_name.c_str(), epoxyMed, sensor_width / 2, sensor_height / 2, epoxy_thickness / 2); sensor->SetLineColor(kBlue); sensor->SetFillColorAlpha(kBlue, 1.0); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(x_offset + active_x_shift, y + y_offset, mZ + z_offset - epoxy_thickness / 2)); @@ -612,14 +615,14 @@ void FT3Module::create_layout(double mZ, int layerNumber, int direction, double // FPC-to-support epoxy glue std::string glue_down_name = "FT3glue_down_back_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(glue_down_name.c_str(), epoxyMed, sensor_width / 2, sensor_height / 2, epoxy_thickness / 2); + sensor = geoManager->MakeBox(glue_down_name.c_str(), epoxyMed, sensor_width / 2, sensor_height / 2, epoxy_thickness / 2); sensor->SetLineColor(kBlue); sensor->SetFillColorAlpha(kBlue, 1.0); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(x_offset + active_x_shift, y + y_offset, mZ + z_offset + epoxy_thickness / 2)); // Kapton std::string fpc_name = "FT3fpc_back_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(fpc_name.c_str(), kaptonMed, sensor_width / 2, sensor_height / 2, kapton_thickness / 2); + sensor = geoManager->MakeBox(fpc_name.c_str(), kaptonMed, sensor_width / 2, sensor_height / 2, kapton_thickness / 2); sensor->SetLineColor(kGreen); sensor->SetFillColorAlpha(kGreen, 0.4); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(active_x_shift + x_offset, y + y_offset, mZ + z_offset + epoxy_thickness + kapton_thickness / 2)); @@ -627,14 +630,14 @@ void FT3Module::create_layout(double mZ, int layerNumber, int direction, double if (r_squared < R_material_threshold * R_material_threshold) { // replace copper with alu std::string alu_name = "FT3aluminum_back_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(alu_name.c_str(), AluminumMed, sensor_width / 2, sensor_height / 2, copper_thickness / 2); + sensor = geoManager->MakeBox(alu_name.c_str(), AluminumMed, sensor_width / 2, sensor_height / 2, copper_thickness / 2); sensor->SetLineColor(kBlack); sensor->SetFillColorAlpha(kBlack, 0.4); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(active_x_shift + x_offset, y + y_offset, mZ + z_offset + epoxy_thickness + kapton_thickness + copper_thickness / 2)); } else { std::string copper_name = "FT3copper_back_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(copper_name.c_str(), copperMed, sensor_width / 2, sensor_height / 2, copper_thickness / 2); + sensor = geoManager->MakeBox(copper_name.c_str(), copperMed, sensor_width / 2, sensor_height / 2, copper_thickness / 2); sensor->SetLineColor(kBlack); sensor->SetFillColorAlpha(kBlack, 0.4); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(active_x_shift + x_offset, y + y_offset, mZ + z_offset + epoxy_thickness + kapton_thickness + copper_thickness / 2)); @@ -642,7 +645,7 @@ void FT3Module::create_layout(double mZ, int layerNumber, int direction, double // silicon-to-FPC epoxy glue std::string glue_up_name = "FT3glue_up_back_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(glue_up_name.c_str(), epoxyMed, sensor_width / 2, sensor_height / 2, epoxy_thickness / 2); + sensor = geoManager->MakeBox(glue_up_name.c_str(), epoxyMed, sensor_width / 2, sensor_height / 2, epoxy_thickness / 2); sensor->SetLineColor(kBlue); sensor->SetFillColorAlpha(kBlue, 1.0); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(x_offset + active_x_shift, y + y_offset, mZ + z_offset + epoxy_thickness + kapton_thickness + copper_thickness + epoxy_thickness / 2)); @@ -650,13 +653,13 @@ void FT3Module::create_layout(double mZ, int layerNumber, int direction, double if (sensor_width == 2.5) { std::string sensor_name = "FT3sensor_back_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(sensor_name.c_str(), siliconMed, active_width / 2, active_height / 2, silicon_thickness / 2); + sensor = geoManager->MakeBox(sensor_name.c_str(), siliconMed, active_width / 2, active_height / 2, silicon_thickness / 2); sensor->SetLineColor(SiColor); sensor->SetFillColorAlpha(SiColor, 0.4); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(active_x_shift_sensor + x_offset, y + y_offset, mZ + z_offset + epoxy_thickness + kapton_thickness + copper_thickness + epoxy_thickness + silicon_thickness / 2)); std::string inactive_name = "FT3inactive_back_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(inactive_name.c_str(), siliconMed, (sensor_width - active_width) / 2, sensor_height / 2, silicon_thickness / 2); + sensor = geoManager->MakeBox(inactive_name.c_str(), siliconMed, (sensor_width - active_width) / 2, sensor_height / 2, silicon_thickness / 2); sensor->SetLineColor(kRed); sensor->SetFillColorAlpha(kRed, 1.0); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(x_offset + inactive_x_shift, y + y_offset, mZ + z_offset + epoxy_thickness + kapton_thickness + copper_thickness + epoxy_thickness + silicon_thickness / 2)); @@ -664,21 +667,21 @@ void FT3Module::create_layout(double mZ, int layerNumber, int direction, double } else { // active (4.6 cm centered) std::string sensor_name = "FT3sensor_back_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(sensor_name.c_str(), siliconMed, active_width / 2, sensor_height / 2, silicon_thickness / 2); + sensor = geoManager->MakeBox(sensor_name.c_str(), siliconMed, active_width / 2, sensor_height / 2, silicon_thickness / 2); sensor->SetLineColor(SiColor); sensor->SetFillColorAlpha(SiColor, 0.4); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(x_offset + x_shifted + inactive_width / 2, y + y_offset, mZ + z_offset + epoxy_thickness + kapton_thickness + copper_thickness + epoxy_thickness + silicon_thickness / 2)); // left inactive strip std::string inactive_name_left = "FT3inactive_left_back_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(inactive_name_left.c_str(), siliconMed, inactive_width / 2, sensor_height / 2, silicon_thickness / 2); + sensor = geoManager->MakeBox(inactive_name_left.c_str(), siliconMed, inactive_width / 2, sensor_height / 2, silicon_thickness / 2); sensor->SetLineColor(kRed); sensor->SetFillColorAlpha(kRed, 1.0); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(x_offset + inactive_x_shift_left, y + y_offset, mZ + z_offset + epoxy_thickness + kapton_thickness + copper_thickness + epoxy_thickness + silicon_thickness / 2)); // right inactive strip std::string inactive_name_right = "FT3inactive_right_back_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - sensor = gGeoManager->MakeBox(inactive_name_right.c_str(), siliconMed, inactive_width / 2, sensor_height / 2, silicon_thickness / 2); + sensor = geoManager->MakeBox(inactive_name_right.c_str(), siliconMed, inactive_width / 2, sensor_height / 2, silicon_thickness / 2); sensor->SetLineColor(kRed); sensor->SetFillColorAlpha(kRed, 1.0); motherVolume->AddNode(sensor, sensor_count++, new TGeoTranslation(x_offset + inactive_x_shift_right, y + y_offset, mZ + z_offset + epoxy_thickness + kapton_thickness + copper_thickness + epoxy_thickness + silicon_thickness / 2)); @@ -691,9 +694,13 @@ void FT3Module::create_layout(double mZ, int layerNumber, int direction, double rowCounter++; } } + LOG(debug) << "FT3Module: done create_layout"; } void FT3Module::createModule(double mZ, int layerNumber, int direction, double Rin, double Rout, double overlap, const std::string& face, const std::string& layout_type, TGeoVolume* motherVolume) { + + LOG(debug) << "FT3Module: createModule - Layer " << layerNumber << ", Direction " << direction << ", Face " << face; create_layout(mZ, layerNumber, direction, Rin, Rout, overlap, face, layout_type, motherVolume); + LOG(debug) << "FT3Module: done createModule"; } From 705c73cda6dded60f2fe39c724842959b76134b6 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 16 Jan 2026 10:08:08 +0100 Subject: [PATCH 093/234] GPU CUDA: Do not link against nvrtc library, which is not used --- GPU/GPUTracking/Base/cuda/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GPUTracking/Base/cuda/CMakeLists.txt b/GPU/GPUTracking/Base/cuda/CMakeLists.txt index e7a579bec794d..05ed091eb83ea 100644 --- a/GPU/GPUTracking/Base/cuda/CMakeLists.txt +++ b/GPU/GPUTracking/Base/cuda/CMakeLists.txt @@ -148,7 +148,7 @@ if (onnxruntime_FOUND) endif() # Setting target architecture and adding GPU libraries -target_link_libraries(${targetName} PRIVATE cuda cudart nvrtc) +target_link_libraries(${targetName} PRIVATE cuda cudart) set_target_cuda_arch(${targetName}) #target_link_options(${targetName} PRIVATE "LINKER:--version-script=${CMAKE_CURRENT_SOURCE_DIR}/version_script.ld") #set_target_properties(${targetName} PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/version_script.ld) From 36b13b4dde9cce37ed414ea310d8a6a635d4ce31 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 16 Jan 2026 10:36:46 +0100 Subject: [PATCH 094/234] GPU: Fix direct memory allocation debug message --- GPU/GPUTracking/Base/GPUReconstruction.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GPUTracking/Base/GPUReconstruction.cxx b/GPU/GPUTracking/Base/GPUReconstruction.cxx index ef336526080b9..fbbe815f63c33 100644 --- a/GPU/GPUTracking/Base/GPUReconstruction.cxx +++ b/GPU/GPUTracking/Base/GPUReconstruction.cxx @@ -764,7 +764,7 @@ void* GPUReconstruction::AllocateDirectMemory(size_t size, int32_t type) } UpdateMaxMemoryUsed(); if (GetProcessingSettings().allocDebugLevel >= 2) { - std::cout << "Allocated (unmanaged " << (type == GPUMemoryResource::MEMORY_GPU ? "gpu" : "host") << "): " << size << " - available: " << ptrDiff(poolend, pool) << "\n"; + std::cout << "Allocated (unmanaged " << ((type & GPUMemoryResource::MEMORY_GPU) ? "gpu" : "host") << "): " << size << " - available: " << ptrDiff(poolend, pool) << "\n"; } return retVal; } From 9ca7f3a7219d04b10219c6a653b9bf91cd2bf94c Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 16 Jan 2026 10:49:17 +0100 Subject: [PATCH 095/234] GPU: Fix crash with --noEvents option, and improve some debug messages --- .../Standalone/Benchmark/standalone.cxx | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx b/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx index b9825bc6da481..5fa9da23d7423 100644 --- a/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx +++ b/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx @@ -173,7 +173,7 @@ int32_t ReadConfiguration(int argc, char** argv) return 1; } if (configStandalone.proc.doublePipeline && (configStandalone.runs < 4 || !configStandalone.outputcontrolmem)) { - printf("Double pipeline mode needs at least 3 runs per event and external output. To cycle though multiple events, use --preloadEvents and --runs n for n iterations round-robin\n"); + printf("Double pipeline mode needs at least 4 runs per event and external output. To cycle though multiple events, use --preloadEvents and --runs n for n iterations round-robin\n"); return 1; } if (configStandalone.TF.bunchSim && configStandalone.TF.nMerge) { @@ -297,7 +297,8 @@ int32_t SetupReconstruction() printf("Error reading event config file\n"); return 1; } - printf("Read event settings from dir %s (solenoidBz: %f, constBz %d, maxTimeBin %d)\n", eventsDir.c_str(), rec->GetGRPSettings().solenoidBzNominalGPU, (int32_t)rec->GetGRPSettings().constBz, rec->GetGRPSettings().grpContinuousMaxTimeBin); + const char* tmptext = configStandalone.noEvents ? "Using default event settings, no event dir loaded" : "Read event settings from dir "; + printf("%s%s (solenoidBz: %f, constBz %d, maxTimeBin %d)\n", tmptext, configStandalone.noEvents ? "" : eventsDir.c_str(), rec->GetGRPSettings().solenoidBzNominalGPU, (int32_t)rec->GetGRPSettings().constBz, rec->GetGRPSettings().grpContinuousMaxTimeBin); if (configStandalone.testSyncAsync) { recAsync->ReadSettings(eventsDir.c_str()); } @@ -781,13 +782,17 @@ int32_t main(int argc, char** argv) srand(configStandalone.seed); - for (nEventsInDirectory = 0; true; nEventsInDirectory++) { - std::ifstream in; - in.open((eventsDir + GPUCA_EVDUMP_FILE "." + std::to_string(nEventsInDirectory) + ".dump").c_str(), std::ifstream::binary); - if (in.fail()) { - break; + nEventsInDirectory = 0; + if (!configStandalone.noEvents) { + while (true) { + std::ifstream in; + in.open((eventsDir + GPUCA_EVDUMP_FILE "." + std::to_string(nEventsInDirectory) + ".dump").c_str(), std::ifstream::binary); + if (in.fail()) { + break; + } + in.close(); + nEventsInDirectory++; } - in.close(); } if (configStandalone.TF.bunchSim || configStandalone.TF.nMerge) { @@ -824,11 +829,7 @@ int32_t main(int argc, char** argv) fflush(stdout); for (int32_t i = 0; i < nEvents - configStandalone.StartEvent; i++) { LoadEvent(configStandalone.StartEvent + i, i); - if (configStandalone.proc.debugLevel >= 2) { - printf("Loading event %d\n", i); - } else { - printf(" %d", i); - } + printf(configStandalone.proc.debugLevel >= 2 ? "Loading event %d\n" : " %d", i + configStandalone.StartEvent); fflush(stdout); } printf("\n"); @@ -856,7 +857,7 @@ int32_t main(int argc, char** argv) if (iEvent != configStandalone.StartEvent) { printf("\n"); } - if (configStandalone.noEvents == false && !configStandalone.preloadEvents) { + if (!configStandalone.noEvents && !configStandalone.preloadEvents) { HighResTimer timerLoad; timerLoad.Start(); if (LoadEvent(iEvent, 0)) { @@ -889,12 +890,14 @@ int32_t main(int argc, char** argv) } printf("Loading time: %'d us\n", (int32_t)(1000000 * timerLoad.GetCurrentElapsedTime())); } - printf("Processing Event %d\n", iEvent); nIteration.store(0); nIterationEnd.store(0); double pipelineWalltime = 1.; - if (configStandalone.proc.doublePipeline) { + if (configStandalone.noEvents) { + printf("No processing, no events loaded\n"); + } else if (configStandalone.proc.doublePipeline) { + printf(configStandalone.preloadEvents ? "Processing Events %d to %d in Pipeline\n" : "Processing Event %d in Pipeline %d times\n", iEvent, configStandalone.preloadEvents ? std::min(iEvent + configStandalone.runs - 1, nEvents - 1) : configStandalone.runs); HighResTimer timerPipeline; if (configStandalone.proc.debugLevel < 2 && (RunBenchmark(rec, chainTracking, 1, iEvent, &nTracksTotal, &nClustersTotal) || RunBenchmark(recPipeline, chainTrackingPipeline, 2, iEvent, &nTracksTotal, &nClustersTotal))) { goto breakrun; @@ -907,6 +910,7 @@ int32_t main(int argc, char** argv) pipelineWalltime = timerPipeline.GetElapsedTime() / (configStandalone.runs - 2); printf("Pipeline wall time: %f, %d iterations, %f per event\n", timerPipeline.GetElapsedTime(), configStandalone.runs - 2, pipelineWalltime); } else { + printf("Processing Event %d\n", iEvent); if (RunBenchmark(rec, chainTracking, configStandalone.runs, iEvent, &nTracksTotal, &nClustersTotal)) { goto breakrun; } From fbe64c88c1e007d21024fbfd7f799a6fe4b1918a Mon Sep 17 00:00:00 2001 From: shahoian Date: Thu, 15 Jan 2026 22:35:14 +0100 Subject: [PATCH 096/234] Optionally refit ITS outward seeding with inward refit result By default set to false as no effect of repeating this fit was seen so far. --- .../GPU/ITStrackingGPU/TrackingKernels.h | 1 + .../tracking/GPU/cuda/TrackerTraitsGPU.cxx | 1 + .../ITS/tracking/GPU/cuda/TrackingKernels.cu | 32 +++++++++++++++++++ .../include/ITStracking/Configuration.h | 1 + .../include/ITStracking/TrackingConfigParam.h | 1 + .../ITSMFT/ITS/tracking/src/Configuration.cxx | 1 + .../ITSMFT/ITS/tracking/src/TrackerTraits.cxx | 16 ++++++++++ 7 files changed, 53 insertions(+) diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h index a4e4328b3aa22..6e0427f5413ba 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h @@ -219,6 +219,7 @@ void trackSeedHandler(CellSeed* trackSeeds, const float maxChi2ClusterAttachment, const float maxChi2NDF, const int reseedIfShorter, + const bool repeatRefitOut, const bool shiftRefToCluster, const o2::base::Propagator* propagator, const o2::base::PropagatorF::MatCorrType matCorrType, diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx index f94147747a475..c4a5cfb4e26b3 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx @@ -336,6 +336,7 @@ void TrackerTraitsGPU::findRoads(const int iteration) startLevel, // const int startLevel, this->mTrkParams[0].MaxChi2ClusterAttachment, // float maxChi2ClusterAttachment this->mTrkParams[0].MaxChi2NDF, // float maxChi2NDF + this->mTrkParams[0].RepeatRefitOut, this->mTrkParams[0].ReseedIfShorter, this->mTrkParams[0].ShiftRefToCluster, mTimeFrameGPU->getDevicePropagator(), // const o2::base::Propagator* propagator diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu index d9136cb96d00e..85689488f5f6e 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu @@ -291,6 +291,7 @@ GPUg() void __launch_bounds__(256, 1) fitTrackSeedsKernel( const float maxChi2ClusterAttachment, const float maxChi2NDF, const int reseedIfShorter, + const bool repeatRefitOut, const bool shifRefToCluster, const o2::base::Propagator* propagator, const o2::base::PropagatorF::MatCorrType matCorrType) @@ -337,6 +338,34 @@ GPUg() void __launch_bounds__(256, 1) fitTrackSeedsKernel( if (!fitSuccess || temporaryTrack.getPt() < minPts[nLayers - temporaryTrack.getNClusters()]) { continue; } + if (repeatRefitOut) { // repeat outward refit seeding and linearizing with the stable inward fit result + o2::track::TrackParCov saveInw{temporaryTrack}; + linRef = saveInw; // use refitted track as lin.reference + float saveChi2 = temporaryTrack.getChi2(); + temporaryTrack.resetCovariance(); + temporaryTrack.setCov(temporaryTrack.getQ2Pt() * temporaryTrack.getQ2Pt() * temporaryTrack.getCov()[o2::track::CovLabels::kSigQ2Pt2], o2::track::CovLabels::kSigQ2Pt2); + temporaryTrack.setChi2(0); + fitSuccess = fitTrack(temporaryTrack, // TrackITSExt& track, + 0, // int lastLayer, + nLayers, // int firstLayer, + 1, // int firstCluster, + maxChi2ClusterAttachment, // float maxChi2ClusterAttachment, + maxChi2NDF, // float maxChi2NDF, + o2::constants::math::VeryBig, // float maxQoverPt, + 0, // nCl, + bz, // float bz, + foundTrackingFrameInfo, // TrackingFrameInfo** trackingFrameInfo, + propagator, // const o2::base::Propagator* propagator, + matCorrType, // o2::base::PropagatorF::MatCorrType matCorrType + &linRef, + shifRefToCluster); + if (!fitSuccess) { + continue; + } + temporaryTrack.getParamOut() = temporaryTrack.getParamIn(); + temporaryTrack.getParamIn() = saveInw; + temporaryTrack.setChi2(saveChi2); + } tracks[iCurrentTrackSeedIndex] = temporaryTrack; } } @@ -1174,6 +1203,7 @@ void trackSeedHandler(CellSeed* trackSeeds, const float maxChi2ClusterAttachment, const float maxChi2NDF, const int reseedIfShorter, + const bool repeatRefitOut, const bool shiftRefToCluster, const o2::base::Propagator* propagator, const o2::base::PropagatorF::MatCorrType matCorrType, @@ -1195,6 +1225,7 @@ void trackSeedHandler(CellSeed* trackSeeds, maxChi2ClusterAttachment, // float maxChi2NDF, // float reseedIfShorter, // int + repeatRefitOut, // bool shiftRefToCluster, // bool propagator, // const o2::base::Propagator* matCorrType); // o2::base::PropagatorF::MatCorrType @@ -1375,6 +1406,7 @@ template void trackSeedHandler(CellSeed<7>* trackSeeds, const float maxChi2ClusterAttachment, const float maxChi2NDF, const int reseedIfShorter, + const bool repeatRefitOut, const bool shiftRefToCluster, const o2::base::Propagator* propagator, const o2::base::PropagatorF::MatCorrType matCorrType, diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h index 000c8fe822498..1019a3e3d45a9 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h @@ -69,6 +69,7 @@ struct TrackingParameters { int ReseedIfShorter = 6; // reseed for the final fit track with the length shorter than this std::vector MinPt = {0.f, 0.f, 0.f, 0.f}; unsigned char StartLayerMask = 0x7F; + bool RepeatRefitOut = true; // repeat outward refit using inward refit as a seed bool ShiftRefToCluster = true; // TrackFit: after update shift the linearization reference to cluster bool FindShortTracks = false; bool PerPrimaryVertexProcessing = false; diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h index 2a3506f17fa2f..0529bd53f2073 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h @@ -98,6 +98,7 @@ struct TrackerParamConfig : public o2::conf::ConfigurableParamHelper TrackingMode::getTrackingParameters(TrackingMode p.MinPt[lslot] *= bFactor; } p.ReseedIfShorter = tc.reseedIfShorter; + p.RepeatRefitOut = tc.repeatRefitOut; p.ShiftRefToCluster = tc.shiftRefToCluster; p.createArtefactLabels = tc.createArtefactLabels; diff --git a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx index 6b237ad0a63e8..fe67eadaf6f72 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx @@ -778,6 +778,22 @@ void TrackerTraits::findRoads(const int iteration) if (!fitSuccess || temporaryTrack.getPt() < mTrkParams[iteration].MinPt[mTrkParams[iteration].NLayers - temporaryTrack.getNClusters()]) { return 0; } + if (mTrkParams[0].RepeatRefitOut) { // repeat outward refit seeding and linearizing with the stable inward fit result + o2::track::TrackParCov saveInw{temporaryTrack}; + linRef = saveInw; // use refitted track as lin.reference + float saveChi2 = temporaryTrack.getChi2(); + temporaryTrack.resetCovariance(); + temporaryTrack.setCov(temporaryTrack.getQ2Pt() * temporaryTrack.getQ2Pt() * temporaryTrack.getCov()[o2::track::CovLabels::kSigQ2Pt2], o2::track::CovLabels::kSigQ2Pt2); + temporaryTrack.setChi2(0); + fitSuccess = fitTrack(temporaryTrack, 0, mTrkParams[0].NLayers, 1, mTrkParams[0].MaxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, o2::constants::math::VeryBig, 0, &linRef); + if (!fitSuccess) { + return 0; + } + temporaryTrack.getParamOut() = temporaryTrack.getParamIn(); + temporaryTrack.getParamIn() = saveInw; + temporaryTrack.setChi2(saveChi2); + } + if constexpr (decltype(Tag)::value == PassMode::OnePass::value) { tracks.push_back(temporaryTrack); } else if constexpr (decltype(Tag)::value == PassMode::TwoPassCount::value) { From dd6691384326f1f46bd7e186d1550c116152ea97 Mon Sep 17 00:00:00 2001 From: Ernst Hellbar Date: Mon, 19 Jan 2026 10:52:57 +0100 Subject: [PATCH 097/234] dpl-workflow.sh: increase pvertexer.timeMarginVertexTime to 5 for sync raw pp --- prodtests/full-system-test/dpl-workflow.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index db491da5ebec5..f55605d1da485 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -133,7 +133,7 @@ if [[ $SYNCMODE == 1 ]]; then PVERTEXING_CONFIG_KEY+="pvertexer.meanVertexExtraErrConstraint=0.3;" # for calibration relax the constraint if [[ $SYNCRAWMODE == 1 ]]; then # add extra tolerance in sync mode to account for eventual time misalignment - PVERTEXING_CONFIG_KEY+="pvertexer.timeMarginVertexTime=2.5;" + [[ $BEAMTYPE == "pp" ]] && PVERTEXING_CONFIG_KEY+="pvertexer.timeMarginVertexTime=5;" || PVERTEXING_CONFIG_KEY+="pvertexer.timeMarginVertexTime=2.5;" if [[ -z $ITSEXTRAERR ]]; then # in sync mode account for ITS residual misalignment ERRIB="100e-8" ERROB="100e-8" From c990996954857d60b683fadc3bc037f055276c5d Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Mon, 19 Jan 2026 20:51:36 +0100 Subject: [PATCH 098/234] DPL Analysis: Use dangling edges context in more places (#14953) --- .../AnalysisSupport/src/AODWriterHelpers.cxx | 21 ++++--- .../CCDBSupport/src/AnalysisCCDBHelpers.cxx | 59 ++++++++++--------- .../CCDBSupport/src/AnalysisCCDBHelpers.h | 2 +- .../Core/include/Framework/AnalysisTask.h | 4 +- Framework/Core/src/AnalysisSupportHelpers.cxx | 4 +- 5 files changed, 45 insertions(+), 45 deletions(-) diff --git a/Framework/AnalysisSupport/src/AODWriterHelpers.cxx b/Framework/AnalysisSupport/src/AODWriterHelpers.cxx index d868b7498fb76..b76ffca13977e 100644 --- a/Framework/AnalysisSupport/src/AODWriterHelpers.cxx +++ b/Framework/AnalysisSupport/src/AODWriterHelpers.cxx @@ -62,13 +62,13 @@ const static std::unordered_map ROOTfileNa AlgorithmSpec AODWriterHelpers::getOutputTTreeWriter(ConfigContext const& ctx) { - auto& ac = ctx.services().get(); auto dod = AnalysisSupportHelpers::getDataOutputDirector(ctx); int compressionLevel = 505; if (ctx.options().hasOption("aod-writer-compression")) { compressionLevel = ctx.options().get("aod-writer-compression"); } - return AlgorithmSpec{[dod, outputInputs = ac.outputsInputsAOD, compressionLevel](InitContext& ic) -> std::function { + return AlgorithmSpec{[dod, compressionLevel](InitContext& ic) -> std::function { + auto outputInputs = ic.services().get().outputsInputsAOD; LOGP(debug, "======== getGlobalAODSink::Init =========="); // find out if any table needs to be saved @@ -241,14 +241,13 @@ AlgorithmSpec AODWriterHelpers::getOutputTTreeWriter(ConfigContext const& ctx) }; } -AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& ctx) +AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& /*ctx*/) { - using namespace monitoring; - auto& ac = ctx.services().get(); - auto tskmap = ac.outTskMap; - auto objmap = ac.outObjHistMap; - - return AlgorithmSpec{[objmap, tskmap](InitContext& ic) -> std::function { + return AlgorithmSpec{[](InitContext& ic) -> std::function { + using namespace monitoring; + auto& dec = ic.services().get(); + auto tskmap = dec.outTskMap; + auto objmap = dec.outObjHistMap; auto& callbacks = ic.services().get(); auto inputObjects = std::make_shared>>(); @@ -278,7 +277,7 @@ AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& ctx) callbacks.set(endofdatacb); return [inputObjects, objmap, tskmap](ProcessingContext& pc) mutable -> void { - auto mergePart = [&inputObjects, &objmap, &tskmap, &pc](DataRef const& ref) { + auto mergePart = [&inputObjects, &objmap, &tskmap](DataRef const& ref) { O2_SIGNPOST_ID_GENERATE(hid, histogram_registry); O2_SIGNPOST_START(histogram_registry, hid, "mergePart", "Merging histogram"); if (!ref.header) { @@ -474,7 +473,7 @@ AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& ctx) }; O2_SIGNPOST_ID_GENERATE(rid, histogram_registry); O2_SIGNPOST_START(histogram_registry, rid, "processParts", "Start merging %zu parts received together.", pc.inputs().getNofParts(0)); - for (int pi = 0; pi < pc.inputs().getNofParts(0); ++pi) { + for (auto pi = 0U; pi < pc.inputs().getNofParts(0); ++pi) { mergePart(pc.inputs().get("x", pi)); } O2_SIGNPOST_END(histogram_registry, rid, "processParts", "Done histograms in multipart message."); diff --git a/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx b/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx index 9ec911518f754..413adfddecf04 100644 --- a/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx +++ b/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx @@ -67,38 +67,39 @@ void fillValidRoutes(CCDBFetcherHelper& helper, std::vector(); - std::vector> schemas; - auto schemaMetadata = std::make_shared(); + return adaptStateful([](ConfigParamRegistry const& options, DeviceSpec const& spec, InitContext& ic) { + auto& dec = ic.services().get(); + std::vector> schemas; + auto schemaMetadata = std::make_shared(); - for (auto& input : ac.analysisCCDBInputs) { - std::vector> fields; - schemaMetadata->Append("outputRoute", DataSpecUtils::describe(input)); - schemaMetadata->Append("outputBinding", input.binding); + for (auto& input : dec.analysisCCDBInputs) { + std::vector> fields; + schemaMetadata->Append("outputRoute", DataSpecUtils::describe(input)); + schemaMetadata->Append("outputBinding", input.binding); - for (auto& m : input.metadata) { - // Save the list of input tables - if (m.name.starts_with("input:")) { - auto name = m.name.substr(6); - schemaMetadata->Append("sourceTable", name); - schemaMetadata->Append("sourceMatcher", DataSpecUtils::describe(std::get(DataSpecUtils::fromMetadataString(m.defaultValue.get()).matcher))); - continue; - } - // Ignore the non ccdb: entries - if (!m.name.starts_with("ccdb:")) { - continue; + for (auto& m : input.metadata) { + // Save the list of input tables + if (m.name.starts_with("input:")) { + auto name = m.name.substr(6); + schemaMetadata->Append("sourceTable", name); + schemaMetadata->Append("sourceMatcher", DataSpecUtils::describe(std::get(DataSpecUtils::fromMetadataString(m.defaultValue.get()).matcher))); + continue; + } + // Ignore the non ccdb: entries + if (!m.name.starts_with("ccdb:")) { + continue; + } + // Create the schema of the output + auto metadata = std::make_shared(); + metadata->Append("url", m.defaultValue.asString()); + auto columnName = m.name.substr(strlen("ccdb:")); + fields.emplace_back(std::make_shared(columnName, arrow::binary_view(), false, metadata)); } - // Create the schema of the output - auto metadata = std::make_shared(); - metadata->Append("url", m.defaultValue.asString()); - auto columnName = m.name.substr(strlen("ccdb:")); - fields.emplace_back(std::make_shared(columnName, arrow::binary_view(), false, metadata)); + schemas.emplace_back(std::make_shared(fields, schemaMetadata)); } - schemas.emplace_back(std::make_shared(fields, schemaMetadata)); - } - return adaptStateful([schemas](CallbackService& callbacks, ConfigParamRegistry const& options, DeviceSpec const& spec) { + std::shared_ptr helper = std::make_shared(); CCDBFetcherHelper::initialiseHelper(*helper, options); std::unordered_map bindings; @@ -129,11 +130,11 @@ AlgorithmSpec AnalysisCCDBHelpers::fetchFromCCDB(ConfigContext const& ctx) int outputRouteIndex = bindings.at(outRouteDesc); auto& spec = helper->routes[outputRouteIndex].matcher; std::vector> builders; - for (auto& _ : schema->fields()) { + for (auto const& _ : schema->fields()) { builders.emplace_back(std::make_shared()); } - for (size_t ci = 0; ci < timestampColumn->num_chunks(); ++ci) { + for (auto ci = 0; ci < timestampColumn->num_chunks(); ++ci) { std::shared_ptr chunk = timestampColumn->chunk(ci); auto const* timestamps = chunk->data()->GetValuesSafe(1); diff --git a/Framework/CCDBSupport/src/AnalysisCCDBHelpers.h b/Framework/CCDBSupport/src/AnalysisCCDBHelpers.h index f8175034da0ba..3be2138bd2b5c 100644 --- a/Framework/CCDBSupport/src/AnalysisCCDBHelpers.h +++ b/Framework/CCDBSupport/src/AnalysisCCDBHelpers.h @@ -17,7 +17,7 @@ namespace o2::framework { struct AnalysisCCDBHelpers { - static AlgorithmSpec fetchFromCCDB(ConfigContext const& ctx); + static AlgorithmSpec fetchFromCCDB(ConfigContext const&); }; } // namespace o2::framework diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index c50b5358990de..4f8a9e719e4b9 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -521,7 +521,7 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) std::vector expressionInfos; /// make sure options and configurables are set before expression infos are created - homogeneous_apply_refs([&options, &hash](auto& element) { return analysis_task_parsers::appendOption(options, element); }, *task.get()); + homogeneous_apply_refs([&options](auto& element) { return analysis_task_parsers::appendOption(options, element); }, *task.get()); /// extract conditions and append them as inputs homogeneous_apply_refs([&inputs](auto& element) { return analysis_task_parsers::appendCondition(inputs, element); }, *task.get()); @@ -620,7 +620,7 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) } // reset pre-slice for the next dataframe auto slices = pc.services().get(); - homogeneous_apply_refs([&pc, &slices](auto& element) { + homogeneous_apply_refs([&slices](auto& element) { return analysis_task_parsers::updateSliceInfo(element, slices); }, *(task.get())); diff --git a/Framework/Core/src/AnalysisSupportHelpers.cxx b/Framework/Core/src/AnalysisSupportHelpers.cxx index 15b56f9afbff5..7edf9a2d8d27f 100644 --- a/Framework/Core/src/AnalysisSupportHelpers.cxx +++ b/Framework/Core/src/AnalysisSupportHelpers.cxx @@ -98,7 +98,7 @@ std::shared_ptr AnalysisSupportHelpers::getDataOutputDirecto if (!keepString.empty()) { dod->reset(); std::string d("dangling"); - if (d.find(keepString) == 0) { + if (d.starts_with(keepString) == 0) { // use the dangling outputs std::vector danglingOutputs; for (auto ii = 0u; ii < OutputsInputs.size(); ii++) { @@ -144,7 +144,7 @@ void AnalysisSupportHelpers::addMissingOutputsToSpawner(std::vector sinks::append_to{publisher.outputs}; // append them to the publisher outputs std::vector additionalInputs; - for (auto& input : requestedSpecials | views::filter_not_matching(providedSpecials)) { + for (auto const& input : requestedSpecials | views::filter_not_matching(providedSpecials)) { input.metadata | views::filter_string_params_with("input:") | views::params_to_input_specs() | From a6471db3246688e5ad4302754449cc9b6f756a81 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Mon, 19 Jan 2026 13:59:07 +0100 Subject: [PATCH 099/234] DPL: more preparation for earlier forwarding Separate code in a different commit to minimize the critical changes. --- Framework/Core/src/DataProcessingDevice.cxx | 60 +++++++++++++++++++++ Framework/Core/src/DataRelayer.cxx | 9 ++-- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index 343b567d8b852..91f5fd0c2d547 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -617,6 +617,20 @@ static auto forwardInputs = [](ServiceRegistryRef registry, TimesliceSlot slot, O2_SIGNPOST_END(forwarding, sid, "forwardInputs", "Forwarding done"); }; +static auto cleanEarlyForward = [](ServiceRegistryRef registry, TimesliceSlot slot, std::vector& currentSetOfInputs, + TimesliceIndex::OldestOutputInfo oldestTimeslice, bool copy, bool consume = true) { + auto& proxy = registry.get(); + + O2_SIGNPOST_ID_GENERATE(sid, forwarding); + O2_SIGNPOST_START(forwarding, sid, "forwardInputs", "Cleaning up slot %zu with oldestTimeslice %zu %{public}s%{public}s%{public}s", + slot.index, oldestTimeslice.timeslice.value, copy ? "with copy" : "", copy && consume ? " and " : "", consume ? "with consume" : ""); + // Always copy them, because we do not want to actually send them. + // We merely need the side effect of the consume, if applicable. + auto forwardedParts = DataProcessingHelpers::routeForwardedMessageSet(proxy, currentSetOfInputs, true, consume); + + O2_SIGNPOST_END(forwarding, sid, "forwardInputs", "Forwarding done"); +}; + extern volatile int region_read_global_dummy_variable; volatile int region_read_global_dummy_variable; @@ -1680,6 +1694,51 @@ struct WaitBackpressurePolicy { } }; +auto forwardOnInsertion(ServiceRegistryRef& ref, std::span& messages) -> void +{ + O2_SIGNPOST_ID_GENERATE(sid, forwarding); + + auto& spec = ref.get(); + auto& context = ref.get(); + if (!context.canForwardEarly || spec.forwards.empty()) { + O2_SIGNPOST_EVENT_EMIT(device, sid, "device", "Early forwardinding not enabled / needed."); + return; + } + + O2_SIGNPOST_EVENT_EMIT(device, sid, "device", "Early forwardinding before injecting data into relayer."); + auto& timesliceIndex = ref.get(); + auto oldestTimeslice = timesliceIndex.getOldestPossibleOutput(); + + auto& proxy = ref.get(); + + O2_SIGNPOST_START(forwarding, sid, "forwardInputs", + "Starting forwarding for incoming messages with oldestTimeslice %zu with copy", + oldestTimeslice.timeslice.value); + std::vector forwardedParts(proxy.getNumForwardChannels()); + DataProcessingHelpers::routeForwardedMessages(proxy, messages, forwardedParts, true, false); + + for (int fi = 0; fi < proxy.getNumForwardChannels(); fi++) { + if (forwardedParts[fi].Size() == 0) { + continue; + } + ForwardChannelInfo info = proxy.getForwardChannelInfo(ChannelIndex{fi}); + auto& parts = forwardedParts[fi]; + if (info.policy == nullptr) { + O2_SIGNPOST_EVENT_EMIT_ERROR(forwarding, sid, "forwardInputs", "Forwarding to %{public}s %d has no policy.", info.name.c_str(), fi); + continue; + } + O2_SIGNPOST_EVENT_EMIT(forwarding, sid, "forwardInputs", "Forwarding to %{public}s %d", info.name.c_str(), fi); + info.policy->forward(parts, ChannelIndex{fi}, ref); + } + auto& asyncQueue = ref.get(); + auto& decongestion = ref.get(); + O2_SIGNPOST_ID_GENERATE(aid, async_queue); + O2_SIGNPOST_EVENT_EMIT(async_queue, aid, "forwardInputs", "Queuing forwarding oldestPossible %zu", oldestTimeslice.timeslice.value); + AsyncQueueHelpers::post(asyncQueue, AsyncTask{.timeslice = oldestTimeslice.timeslice, .id = decongestion.oldestPossibleTimesliceTask, .debounce = -1, .callback = decongestionCallbackLate} + .user({.ref = ref, .oldestTimeslice = oldestTimeslice})); + O2_SIGNPOST_END(forwarding, sid, "forwardInputs", "Forwarding done"); +}; + /// This is the inner loop of our framework. The actual implementation /// is divided in two parts. In the first one we define a set of lambdas /// which describe what is actually going to happen, hiding all the state @@ -1854,6 +1913,7 @@ void DataProcessingDevice::handleData(ServiceRegistryRef ref, InputChannelInfo& VariableContextHelpers::getTimeslice(variables); forwardInputs(ref, slot, dropped, oldestOutputInfo, false, true); }; + auto relayed = relayer.relay(parts.At(headerIndex)->GetData(), &parts.At(headerIndex), input, diff --git a/Framework/Core/src/DataRelayer.cxx b/Framework/Core/src/DataRelayer.cxx index ea2c4c0b73316..d9c340cd9c225 100644 --- a/Framework/Core/src/DataRelayer.cxx +++ b/Framework/Core/src/DataRelayer.cxx @@ -499,6 +499,12 @@ DataRelayer::RelayChoice // DataRelayer::relay assert(nPayloads > 0); size_t saved = 0; + // It's guaranteed we will see all these messages only once, so we can + // do the forwarding here. + auto allMessages = std::span(messages, messages + nMessages); + if (onInsertion) { + onInsertion(services, allMessages); + } for (size_t mi = 0; mi < nMessages; ++mi) { assert(mi + nPayloads < nMessages); // We are in calibration mode and the data does not have the calibration bit set. @@ -515,9 +521,6 @@ DataRelayer::RelayChoice continue; } auto span = std::span(messages + mi, messages + mi + nPayloads + 1); - if (onInsertion) { - onInsertion(services, span); - } target.add([&span](size_t i) -> fair::mq::MessagePtr& { return span[i]; }, nPayloads + 1); mi += nPayloads; saved += nPayloads; From ed8276cbddc8b3928c59fd6ee2b68dd60bb6afe1 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Mon, 19 Jan 2026 13:59:07 +0100 Subject: [PATCH 100/234] DPL: earlier forwarding This anticipates the forwarding to the earliest possible moment, i.e. when we are about to insert the messages in a slot. This is the earliest moment we can guarantee messages will be seen only once. --- .../include/Framework/DataProcessingContext.h | 8 ++- Framework/Core/src/DataProcessingDevice.cxx | 53 ++++++++++++++----- Framework/Core/src/DataRelayer.cxx | 2 + 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/Framework/Core/include/Framework/DataProcessingContext.h b/Framework/Core/include/Framework/DataProcessingContext.h index 9b7cbc238c942..221f7b099dc07 100644 --- a/Framework/Core/include/Framework/DataProcessingContext.h +++ b/Framework/Core/include/Framework/DataProcessingContext.h @@ -23,6 +23,12 @@ struct ServiceRegistry; struct DataAllocator; struct DataProcessorSpec; +enum struct ForwardPolicy { + AtInjection, + AtCompletionPolicySatisified, + AfterProcessing +}; + struct DataProcessorContext { DataProcessorContext(DataProcessorContext const&) = delete; DataProcessorContext() = default; @@ -122,7 +128,7 @@ struct DataProcessorContext { mutable std::vector preLoopHandles; /// Wether or not the associated DataProcessor can forward things early - bool canForwardEarly = true; + ForwardPolicy forwardPolicy = ForwardPolicy::AtInjection; bool isSink = false; bool balancingInputs = true; diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index 91f5fd0c2d547..f65477c573772 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -1050,10 +1050,25 @@ void DataProcessingDevice::fillContext(DataProcessorContext& context, DeviceCont }; } - auto decideEarlyForward = [&context, &deviceContext, &spec, this]() -> bool { + auto decideEarlyForward = [&context, &deviceContext, &spec, this]() -> ForwardPolicy { + ForwardPolicy defaultEarlyForwardPolicy = getenv("DPL_OLD_EARLY_FORWARD") ? ForwardPolicy::AtCompletionPolicySatisified : ForwardPolicy::AtInjection; + /// We must make sure there is no optional /// if we want to optimize the forwarding - bool canForwardEarly = (spec.forwards.empty() == false) && deviceContext.processingPolicies.earlyForward != EarlyForwardPolicy::NEVER; + ForwardPolicy forwardPolicy = defaultEarlyForwardPolicy; + if (spec.forwards.empty() == false) { + switch (deviceContext.processingPolicies.earlyForward) { + case o2::framework::EarlyForwardPolicy::NEVER: + forwardPolicy = ForwardPolicy::AfterProcessing; + break; + case o2::framework::EarlyForwardPolicy::ALWAYS: + forwardPolicy = defaultEarlyForwardPolicy; + break; + case o2::framework::EarlyForwardPolicy::NORAW: + forwardPolicy = defaultEarlyForwardPolicy; + break; + } + } bool onlyConditions = true; bool overriddenEarlyForward = false; for (auto& forwarded : spec.forwards) { @@ -1061,25 +1076,25 @@ void DataProcessingDevice::fillContext(DataProcessorContext& context, DeviceCont onlyConditions = false; } if (DataSpecUtils::partialMatch(forwarded.matcher, o2::header::DataDescription{"RAWDATA"}) && deviceContext.processingPolicies.earlyForward == EarlyForwardPolicy::NORAW) { - context.canForwardEarly = false; + forwardPolicy = ForwardPolicy::AfterProcessing; overriddenEarlyForward = true; LOG(detail) << "Cannot forward early because of RAWDATA input: " << DataSpecUtils::describe(forwarded.matcher); break; } if (forwarded.matcher.lifetime == Lifetime::Optional) { - context.canForwardEarly = false; + forwardPolicy = ForwardPolicy::AfterProcessing; overriddenEarlyForward = true; LOG(detail) << "Cannot forward early because of Optional input: " << DataSpecUtils::describe(forwarded.matcher); break; } } if (!overriddenEarlyForward && onlyConditions) { - context.canForwardEarly = true; + forwardPolicy = defaultEarlyForwardPolicy; LOG(detail) << "Enabling early forwarding because only conditions to be forwarded"; } - return canForwardEarly; + return forwardPolicy; }; - context.canForwardEarly = decideEarlyForward(); + context.forwardPolicy = decideEarlyForward(); } void DataProcessingDevice::PreRun() @@ -1700,7 +1715,7 @@ auto forwardOnInsertion(ServiceRegistryRef& ref, std::span auto& spec = ref.get(); auto& context = ref.get(); - if (!context.canForwardEarly || spec.forwards.empty()) { + if (context.forwardPolicy == ForwardPolicy::AfterProcessing || spec.forwards.empty()) { O2_SIGNPOST_EVENT_EMIT(device, sid, "device", "Early forwardinding not enabled / needed."); return; } @@ -1858,7 +1873,7 @@ void DataProcessingDevice::handleData(ServiceRegistryRef ref, InputChannelInfo& stats.updateStats({(int)ProcessingStatsId::ERROR_COUNT, DataProcessingStats::Op::Add, 1}); }; - auto handleValidMessages = [&info, ref, &reportError](std::vector const& inputInfos) { + auto handleValidMessages = [&info, ref, &reportError, &context](std::vector const& inputInfos) { auto& relayer = ref.get(); auto& state = ref.get(); static WaitBackpressurePolicy policy; @@ -1919,7 +1934,7 @@ void DataProcessingDevice::handleData(ServiceRegistryRef ref, InputChannelInfo& input, nMessages, nPayloadsPerHeader, - nullptr, + context.forwardPolicy == ForwardPolicy::AtInjection ? forwardOnInsertion : nullptr, onDrop); switch (relayed.type) { case DataRelayer::RelayChoice::Type::Backpressured: @@ -2333,11 +2348,23 @@ bool DataProcessingDevice::tryDispatchComputation(ServiceRegistryRef ref, std::v bool hasForwards = spec.forwards.empty() == false; bool consumeSomething = action.op == CompletionPolicy::CompletionOp::Consume || action.op == CompletionPolicy::CompletionOp::ConsumeExisting; - if (context.canForwardEarly && hasForwards && consumeSomething) { - O2_SIGNPOST_EVENT_EMIT(device, aid, "device", "Early forwainding: %{public}s.", fmt::format("{}", action.op).c_str()); + if (context.forwardPolicy == ForwardPolicy::AtCompletionPolicySatisified && hasForwards && consumeSomething) { + O2_SIGNPOST_EVENT_EMIT(device, aid, "device", "Early forwarding: %{public}s.", fmt::format("{}", action.op).c_str()); auto& timesliceIndex = ref.get(); forwardInputs(ref, action.slot, currentSetOfInputs, timesliceIndex.getOldestPossibleOutput(), true, action.op == CompletionPolicy::CompletionOp::Consume); + } else if (context.forwardPolicy == ForwardPolicy::AtInjection && hasForwards && consumeSomething) { + // We used to do fowarding here, however we now do it much earlier. + // We still need to clean the inputs which were already consumed + // via ConsumeExisting and which still have an header to hold the slot. + // FIXME: do we? This should really happen when we do the forwarding on + // insertion, because otherwise we lose the relevant information on how to + // navigate the set of headers. We could actually rely on the messageset index, + // is that the right thing to do though? + O2_SIGNPOST_EVENT_EMIT(device, aid, "device", "cleaning early forwarding: %{public}s.", fmt::format("{}", action.op).c_str()); + auto& timesliceIndex = ref.get(); + cleanEarlyForward(ref, action.slot, currentSetOfInputs, timesliceIndex.getOldestPossibleOutput(), true, action.op == CompletionPolicy::CompletionOp::Consume); } + markInputsAsDone(action.slot); uint64_t tStart = uv_hrtime(); @@ -2456,7 +2483,7 @@ bool DataProcessingDevice::tryDispatchComputation(ServiceRegistryRef ref, std::v context.postDispatchingCallbacks(processContext); ref.get().call(o2::framework::ServiceRegistryRef{ref}); } - if ((context.canForwardEarly == false) && hasForwards && consumeSomething) { + if ((context.forwardPolicy == ForwardPolicy::AfterProcessing) && hasForwards && consumeSomething) { O2_SIGNPOST_EVENT_EMIT(device, aid, "device", "Late forwarding"); auto& timesliceIndex = ref.get(); forwardInputs(ref, action.slot, currentSetOfInputs, timesliceIndex.getOldestPossibleOutput(), false, action.op == CompletionPolicy::CompletionOp::Consume); diff --git a/Framework/Core/src/DataRelayer.cxx b/Framework/Core/src/DataRelayer.cxx index d9c340cd9c225..05b64b6ed1dad 100644 --- a/Framework/Core/src/DataRelayer.cxx +++ b/Framework/Core/src/DataRelayer.cxx @@ -521,6 +521,8 @@ DataRelayer::RelayChoice continue; } auto span = std::span(messages + mi, messages + mi + nPayloads + 1); + // Notice this will split [(header, payload), (header, payload)] multiparts + // in N different subParts for the message spec. target.add([&span](size_t i) -> fair::mq::MessagePtr& { return span[i]; }, nPayloads + 1); mi += nPayloads; saved += nPayloads; From 9634a2ee3fd8481f9f222c27eee03d1c459a1b13 Mon Sep 17 00:00:00 2001 From: Felix Weiglhofer Date: Tue, 20 Jan 2026 15:05:24 +0100 Subject: [PATCH 101/234] GPU: Don't override --recoSteps flags in standalone. --- .../Standalone/Benchmark/standalone.cxx | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx b/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx index 5fa9da23d7423..a2e74c45fcb86 100644 --- a/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx +++ b/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx @@ -413,6 +413,18 @@ int32_t SetupReconstruction() steps.steps.setBits(gpudatatypes::RecoStep::TPCClusterFinding, false); } + // Set settings for synchronous + GPUChainTracking::ApplySyncSettings(procSet, recSet, steps.steps, configStandalone.testSyncAsync || configStandalone.testSync, configStandalone.rundEdx); + int32_t runAsyncQA = procSet.runQA && !configStandalone.testSyncAsyncQcInSync ? procSet.runQA : 0; + if (configStandalone.testSyncAsync) { + procSet.eventDisplay = nullptr; + if (!configStandalone.testSyncAsyncQcInSync) { + procSet.runQA = false; + } + } + + // Apply --recoSteps flag last so it takes precedence + // E.g. ApplySyncSettings might enable TPCdEdx, but might not be needed if only clusterizer was requested if (configStandalone.recoSteps >= 0) { steps.steps &= configStandalone.recoSteps; } @@ -432,16 +444,6 @@ int32_t SetupReconstruction() } } - // Set settings for synchronous - GPUChainTracking::ApplySyncSettings(procSet, recSet, steps.steps, configStandalone.testSyncAsync || configStandalone.testSync, configStandalone.rundEdx); - int32_t runAsyncQA = procSet.runQA && !configStandalone.testSyncAsyncQcInSync ? procSet.runQA : 0; - if (configStandalone.testSyncAsync) { - procSet.eventDisplay = nullptr; - if (!configStandalone.testSyncAsyncQcInSync) { - procSet.runQA = false; - } - } - rec->SetSettings(&grp, &recSet, &procSet, &steps); if (configStandalone.proc.doublePipeline) { recPipeline->SetSettings(&grp, &recSet, &procSet, &steps); From 96a6a753d2e56ec9db66ad200d693589a188f30a Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 21 Jan 2026 11:07:47 +0100 Subject: [PATCH 102/234] GPU QA: Improvements for some plots --- GPU/GPUTracking/Definitions/GPUSettingsList.h | 5 +- GPU/GPUTracking/qa/GPUQA.cxx | 62 ++++++++++--------- GPU/GPUTracking/qa/GPUQA.h | 8 +-- 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index d70fac115eab7..9bfe6feb14d8d 100644 --- a/GPU/GPUTracking/Definitions/GPUSettingsList.h +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -527,9 +527,10 @@ AddOption(histMaxNClusters, uint32_t, 500000000, "", 0, "Maximum number of clust AddOption(minNClFindable, uint32_t, 70, "", 0, "Minimum number of (weighted) MC clusters for a track to count as findable") AddOption(minNClEff, uint32_t, 10, "", 0, "Minimum number of (weighted) MC clusters for a track to contribute to all-tracks efficiency histogramm") AddOption(minNClRes, uint32_t, 40, "", 0, "Minimum number of (weighted) MC clusters for a track to contribute to resolution histogram") -AddOption(perfFigure, int32_t, 0, "", 0, "Show as performance figure, positive value for MC, negative value for data") +AddOption(perfFigure, std::string, "", "", 0, "Show as performance figure, provide mc/MC or data as asgument, or a custom string", def("MC")) AddOption(plotsDir, std::string, "plots", "", 0, "Directory to write plots to") -AddShortcut("compare", 0, "--QAinput", "Compare QA histograms", "--qa", "--QAinputHistogramsOnly") +AddOption(plotsNoTitle, bool, false, "", 0, "Do not print titles on figures") +AddShortcut("compare", 0, "--QAinput", "Compare QA histograms", "-c", "--qa", "--QAinputHistogramsOnly") AddHelp("help", 'h') EndConfig() diff --git a/GPU/GPUTracking/qa/GPUQA.cxx b/GPU/GPUTracking/qa/GPUQA.cxx index 852ac5c1feefb..b58209efff744 100644 --- a/GPU/GPUTracking/qa/GPUQA.cxx +++ b/GPU/GPUTracking/qa/GPUQA.cxx @@ -413,20 +413,21 @@ void GPUQA::DrawHisto(TH1* histo, char* filename, char* options) void GPUQA::doPerfFigure(float x, float y, float size) { - const char* str_perf_figure_1 = "ALICE Performance"; - const char* str_perf_figure_2_mc = "MC, Pb#minusPb, #sqrt{s_{NN}} = 5.36 TeV"; - const char* str_perf_figure_2_data = "Pb#minusPb, #sqrt{s_{NN}} = 5.36 TeV"; - - if (mConfig.perfFigure == 0) { + if (mConfig.perfFigure == "") { return; } + static constexpr const char* str_perf_figure_1 = "ALICE Performance"; + static constexpr const char* str_perf_figure_2_mc = "MC, Pb#minusPb, #sqrt{s_{NN}} = 5.36 TeV"; + static constexpr const char* str_perf_figure_2_data = "Pb#minusPb, #sqrt{s_{NN}} = 5.36 TeV"; + const char* str_perf_figure_2 = (mConfig.perfFigure == "mc" || mConfig.perfFigure == "MC") ? str_perf_figure_2_mc : (mConfig.perfFigure == "data" ? str_perf_figure_2_data : mConfig.perfFigure.c_str()); + TLatex* t = createGarbageCollected(); // TODO: We could perhaps put everything in a legend, to get a white background if there is a grid t->SetNDC(kTRUE); t->SetTextColor(1); t->SetTextSize(size); t->DrawLatex(x, y, str_perf_figure_1); t->SetTextSize(size * 0.8); - t->DrawLatex(x, y - 0.01 - size, mConfig.perfFigure > 0 ? str_perf_figure_2_mc : str_perf_figure_2_data); + t->DrawLatex(x, y - 0.01 - size, str_perf_figure_2); } void GPUQA::SetMCTrackRange(int32_t min, int32_t max) @@ -539,7 +540,7 @@ int32_t GPUQA::InitQACreateHistograms() createHist(mNCl[i], name, name, 160, 0, 159); } std::unique_ptr binsPt{CreateLogAxis(AXIS_BINS[4], PT_MIN_CLUST, PT_MAX)}; - createHist(mTracks, "tracks_pt", "tracks_pt", AXIS_BINS[4], binsPt.get()); + createHist(mTrackPt, "tracks_pt", "tracks_pt", AXIS_BINS[4], binsPt.get()); const uint32_t maxTime = (mTracking && mTracking->GetParam().continuousMaxTimeBin > 0) ? mTracking->GetParam().continuousMaxTimeBin : TPC_MAX_TIME_BIN_TRIGGERED; createHist(mT0[0], "tracks_t0", "tracks_t0", (maxTime + 1) / 10, 0, maxTime); createHist(mT0[1], "tracks_t0_res", "tracks_t0_res", 1000, -100, 100); @@ -1738,7 +1739,7 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx if (!track.OK()) { continue; } - mTracks->Fill(1.f / fabsf(track.GetParam().GetQPt())); + mTrackPt->Fill(1.f / fabsf(track.GetParam().GetQPt())); mNCl[0]->Fill(track.NClustersFitted()); uint32_t nClCorrected = 0; const auto& trackClusters = mTracking->mIOPtrs.mergedTrackHits; @@ -2247,12 +2248,12 @@ int32_t GPUQA::DrawQAHistograms(TObjArray* qcout) // Create Canvas for track statistic histos if (mQATasks & taskTrackStatistics) { - mCTracks = createGarbageCollected("ctrackspt", "ctrackspt", 0, 0, 700, 700. * 2. / 3.); - mCTracks->cd(); - mPTracks = createGarbageCollected("p0", "", 0.0, 0.0, 1.0, 1.0); - mPTracks->Draw(); - mLTracks = createGarbageCollected(0.9 - legendSpacingString * 1.5, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); - SetLegend(mLTracks, true); + mCTrackPt = createGarbageCollected("ctrackspt", "ctrackspt", 0, 0, 700, 700. * 2. / 3.); + mCTrackPt->cd(); + mPTrackPt = createGarbageCollected("p0", "", 0.0, 0.0, 1.0, 1.0); + mPTrackPt->Draw(); + mLTrackPt = createGarbageCollected(0.9 - legendSpacingString * 1.5, 0.93 - (0.93 - 0.86) / 2. * (float)ConfigNumInputs, 0.98, 0.949); + SetLegend(mLTrackPt, true); for (int32_t i = 0; i < 2; i++) { snprintf(name, 2048, "ctrackst0%d", i); @@ -2800,7 +2801,7 @@ int32_t GPUQA::DrawQAHistograms(TObjArray* qcout) continue; } - e->SetTitle(CLUSTER_TITLES[i]); + e->SetTitle(mConfig.plotsNoTitle ? "" : CLUSTER_TITLES[i]); e->GetYaxis()->SetTitle(i == 0 ? "Number of TPC clusters" : i == 1 ? "Fraction of TPC clusters" : CLUST_HIST_INT_SUM ? "Total TPC clusters (integrated)" : "Fraction of TPC clusters (integrated)"); e->GetXaxis()->SetTitle("#it{p}_{Tmc} (GeV/#it{c})"); e->GetXaxis()->SetTitleOffset(1.1); @@ -2878,7 +2879,7 @@ int32_t GPUQA::DrawQAHistograms(TObjArray* qcout) } title += ")"; - e->SetTitle(title.c_str()); + e->SetTitle(mConfig.plotsNoTitle ? "" : title.c_str()); e->GetXaxis()->SetTitle(i == 3 ? "Local Occupancy" : (i ? "#Phi_{Cl} (sector)" : "First MC Pad Row")); e->GetYaxis()->SetTitle("First Pad Row"); e->Draw(); @@ -2910,7 +2911,7 @@ int32_t GPUQA::DrawQAHistograms(TObjArray* qcout) // Process track statistic histograms float tmpMax = 0.; for (int32_t k = 0; k < ConfigNumInputs; k++) { // TODO: Simplify this drawing, avoid copy&paste - TH1F* e = mTracks; + TH1F* e = mTrackPt; if (GetHist(e, tin, k, nNewInput) == nullptr) { continue; } @@ -2919,10 +2920,10 @@ int32_t GPUQA::DrawQAHistograms(TObjArray* qcout) tmpMax = e->GetMaximum(); } } - mPTracks->cd(); - mPTracks->SetLogx(); + mPTrackPt->cd(); + mPTrackPt->SetLogx(); for (int32_t k = 0; k < ConfigNumInputs; k++) { - TH1F* e = mTracks; + TH1F* e = mTrackPt; if (GetHist(e, tin, k, nNewInput) == nullptr) { continue; } @@ -2933,9 +2934,10 @@ int32_t GPUQA::DrawQAHistograms(TObjArray* qcout) e->SetMinimum(tmpMax * -0.02); e->SetStats(kFALSE); e->SetLineWidth(1); - e->SetTitle("Number of Tracks vs #it{p}_{T}"); + e->SetTitle(mConfig.plotsNoTitle ? "" : "Number of Tracks vs #it{p}_{T}"); e->GetYaxis()->SetTitle("Number of Tracks"); e->GetXaxis()->SetTitle("#it{p}_{T} (GeV/#it{c})"); + e->GetXaxis()->SetTitleOffset(1.2); if (qcout) { qcout->Add(e); } @@ -2943,14 +2945,14 @@ int32_t GPUQA::DrawQAHistograms(TObjArray* qcout) e->SetLineColor(colorNums[k % COLORCOUNT]); e->Draw(k == 0 ? "" : "same"); GetName(fname, k, mConfig.inputHistogramsOnly); - mLTracks->AddEntry(e, Form(mConfig.inputHistogramsOnly ? "%s" : "%sTrack #it{p}_{T}", fname), "l"); + mLTrackPt->AddEntry(e, Form(mConfig.inputHistogramsOnly ? "%s" : "%sTrack #it{p}_{T}", fname), "l"); } - mLTracks->Draw(); + mLTrackPt->Draw(); doPerfFigure(0.63, 0.7, 0.030); - mCTracks->cd(); - mCTracks->Print(Form("%s/tracks.pdf", mConfig.plotsDir.c_str())); + mCTrackPt->cd(); + mCTrackPt->Print(Form("%s/tracks.pdf", mConfig.plotsDir.c_str())); if (mConfig.writeFileExt != "") { - mCTracks->Print(Form("%s/tracks.%s", mConfig.plotsDir.c_str(), mConfig.writeFileExt.c_str())); + mCTrackPt->Print(Form("%s/tracks.%s", mConfig.plotsDir.c_str(), mConfig.writeFileExt.c_str())); } for (int32_t i = 0; i < 2; i++) { @@ -2978,7 +2980,7 @@ int32_t GPUQA::DrawQAHistograms(TObjArray* qcout) e->SetMinimum(tmpMax * -0.02); e->SetStats(kFALSE); e->SetLineWidth(1); - e->SetTitle(i ? "Track t_{0} resolution" : "Track t_{0} distribution"); + e->SetTitle(mConfig.plotsNoTitle ? "" : (i ? "Track t_{0} resolution" : "Track t_{0} distribution")); e->GetYaxis()->SetTitle("a.u."); e->GetXaxis()->SetTitle(i ? "t_{0} - t_{0, mc}" : "t_{0}"); if (qcout) { @@ -3022,7 +3024,7 @@ int32_t GPUQA::DrawQAHistograms(TObjArray* qcout) e->SetMinimum(tmpMax * -0.02); e->SetStats(kFALSE); e->SetLineWidth(1); - e->SetTitle(i ? "Number of Rows with attached Cluster" : "Number of Clusters"); + e->SetTitle(mConfig.plotsNoTitle ? "" : (i ? "Number of Rows with attached Cluster" : "Number of Clusters")); e->GetYaxis()->SetTitle("a.u."); e->GetXaxis()->SetTitle(i ? "N_{Rows with Clusters}" : "N_{Clusters}"); if (qcout) { @@ -3061,7 +3063,7 @@ int32_t GPUQA::DrawQAHistograms(TObjArray* qcout) mClRej[i]->Write(); } mPClRej[i]->cd(); - mClRej[i]->SetTitle(REJECTED_NAMES[i]); + mClRej[i]->SetTitle(mConfig.plotsNoTitle ? "" : REJECTED_NAMES[i]); mClRej[i]->SetOption("colz"); mClRej[i]->Draw(); mCClRej[i]->cd(); @@ -3098,7 +3100,7 @@ int32_t GPUQA::DrawQAHistograms(TObjArray* qcout) delete proj2; e->SetMinimum(-0.02); e->SetMaximum(0.22); - e->SetTitle("Rejected Clusters"); + e->SetTitle(mConfig.plotsNoTitle ? "" : "Rejected Clusters"); e->GetXaxis()->SetTitle("Pad Row"); e->GetYaxis()->SetTitle("Rejected Clusters (fraction)"); e->Draw(k == 0 ? "" : "same"); diff --git a/GPU/GPUTracking/qa/GPUQA.h b/GPU/GPUTracking/qa/GPUQA.h index 346c56a898806..bd3c9be3a9aa5 100644 --- a/GPU/GPUTracking/qa/GPUQA.h +++ b/GPU/GPUTracking/qa/GPUQA.h @@ -290,10 +290,10 @@ class GPUQA double nUnaccessible = 0; } mClusterCounts; - TH1F* mTracks; - TCanvas* mCTracks; - TPad* mPTracks; - TLegend* mLTracks; + TH1F* mTrackPt; + TCanvas* mCTrackPt; + TPad* mPTrackPt; + TLegend* mLTrackPt; TH1F* mNCl[2]; TCanvas* mCNCl[2]; From a4989384162de86181f18515a2431fab19182ed8 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 20 Jan 2026 10:32:03 +0100 Subject: [PATCH 103/234] DPL: avoid needless copy of messages when cleaning up early forwarding --- .../include/Framework/DataProcessingHelpers.h | 2 + Framework/Core/src/DataProcessingDevice.cxx | 7 ++- Framework/Core/src/DataProcessingHelpers.cxx | 54 +++++++++++++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/Framework/Core/include/Framework/DataProcessingHelpers.h b/Framework/Core/include/Framework/DataProcessingHelpers.h index a9bd95b69f4c7..87aeeb8922da3 100644 --- a/Framework/Core/include/Framework/DataProcessingHelpers.h +++ b/Framework/Core/include/Framework/DataProcessingHelpers.h @@ -59,6 +59,8 @@ struct DataProcessingHelpers { /// Helper to route messages for forwarding static void routeForwardedMessages(FairMQDeviceProxy& proxy, std::span& currentSetOfInputs, std::vector& forwardedParts, bool copy, bool consume); + + static void cleanForwardedMessages(std::span& currentSetOfInputs, bool consume); }; } // namespace o2::framework #endif // O2_FRAMEWORK_DATAPROCESSINGHELPERS_H_ diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index f65477c573772..38c57c66c8a01 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -626,9 +626,12 @@ static auto cleanEarlyForward = [](ServiceRegistryRef registry, TimesliceSlot sl slot.index, oldestTimeslice.timeslice.value, copy ? "with copy" : "", copy && consume ? " and " : "", consume ? "with consume" : ""); // Always copy them, because we do not want to actually send them. // We merely need the side effect of the consume, if applicable. - auto forwardedParts = DataProcessingHelpers::routeForwardedMessageSet(proxy, currentSetOfInputs, true, consume); + for (size_t ii = 0, ie = currentSetOfInputs.size(); ii < ie; ++ii) { + auto span = std::span(currentSetOfInputs[ii].messages); + DataProcessingHelpers::cleanForwardedMessages(span, consume); + } - O2_SIGNPOST_END(forwarding, sid, "forwardInputs", "Forwarding done"); + O2_SIGNPOST_END(forwarding, sid, "forwardInputs", "Cleaning done"); }; extern volatile int region_read_global_dummy_variable; diff --git a/Framework/Core/src/DataProcessingHelpers.cxx b/Framework/Core/src/DataProcessingHelpers.cxx index 87e7c9bf8962f..334a0fc6045f6 100644 --- a/Framework/Core/src/DataProcessingHelpers.cxx +++ b/Framework/Core/src/DataProcessingHelpers.cxx @@ -338,6 +338,60 @@ void DataProcessingHelpers::routeForwardedMessages(FairMQDeviceProxy& proxy, std } } +void DataProcessingHelpers::cleanForwardedMessages(std::span& messages, bool consume) +{ + size_t pi = 0; + while (pi < messages.size()) { + auto& header = messages[pi]; + + // If is now possible that the record is not complete when + // we forward it, because of a custom completion policy. + // this means that we need to skip the empty entries in the + // record for being forwarded. + if (header->GetData() == nullptr || + o2::header::get(header->GetData()) || + o2::header::get(header->GetData())) { + pi += 2; + continue; + } + + auto dph = o2::header::get(header->GetData()); + auto dh = o2::header::get(header->GetData()); + + if (dph == nullptr || dh == nullptr) { + // Complain only if this is not an out-of-band message + LOGP(error, "Data is missing {}{}{}", + dph ? "DataProcessingHeader" : "", dph || dh ? "and" : "", dh ? "DataHeader" : ""); + pi += 2; + continue; + } + + // At least one payload. + auto& payload = messages[pi + 1]; + // Calculate the number of messages which should be handled together + // all in one go. + size_t numberOfMessages = 0; + if (dh->splitPayloadParts > 0 && dh->splitPayloadParts == dh->splitPayloadIndex) { + // Sequence of (header, payload[0], ... , payload[splitPayloadParts - 1]) pairs belonging together. + numberOfMessages = dh->splitPayloadParts + 1; // one is for the header + } else { + // Sequence of splitPayloadParts (header, payload) pairs belonging together. + // In case splitPayloadParts = 0, we consider this as a single message pair + numberOfMessages = (dh->splitPayloadParts > 0 ? dh->splitPayloadParts : 1) * 2; + } + + if (payload.get() == nullptr && consume == true) { + // If the payload is not there, it means we already + // processed it with ConsumeExisiting. Therefore we + // need to do something only if this is the last consume. + header.reset(nullptr); + } + + // Nothing to forward go to the next messageset + pi += numberOfMessages; + } +} + auto DataProcessingHelpers::routeForwardedMessageSet(FairMQDeviceProxy& proxy, std::vector& currentSetOfInputs, const bool copyByDefault, bool consume) -> std::vector From 8562189e36996069bd0de7a79c57454ebb3fb8fe Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 21 Jan 2026 16:55:11 +0100 Subject: [PATCH 104/234] DPL: make new early forward optional The new behavior breaks the TPC custom policy. --- Framework/Core/src/DataProcessingDevice.cxx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index 38c57c66c8a01..fb54af9402079 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -1054,7 +1054,11 @@ void DataProcessingDevice::fillContext(DataProcessorContext& context, DeviceCont } auto decideEarlyForward = [&context, &deviceContext, &spec, this]() -> ForwardPolicy { - ForwardPolicy defaultEarlyForwardPolicy = getenv("DPL_OLD_EARLY_FORWARD") ? ForwardPolicy::AtCompletionPolicySatisified : ForwardPolicy::AtInjection; + //ForwardPolicy defaultEarlyForwardPolicy = getenv("DPL_OLD_EARLY_FORWARD") ? ForwardPolicy::AtCompletionPolicySatisified : ForwardPolicy::AtInjection; + // Make the new policy optional until we handle some of the corner cases + // with custom policies which expect the early forward to happen only when + // all the data is available, like in the TPC case. + ForwardPolicy defaultEarlyForwardPolicy = getenv("DPL_NEW_EARLY_FORWARD") ? ForwardPolicy::AtInjection : ForwardPolicy::AtCompletionPolicySatisified; /// We must make sure there is no optional /// if we want to optimize the forwarding From be1d553177b4c8edc9ad47863369f5390f1fefaa Mon Sep 17 00:00:00 2001 From: shahoian Date: Wed, 21 Jan 2026 18:06:42 +0100 Subject: [PATCH 105/234] Store missing GlobalTrackID in the CheckResid output --- Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx b/Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx index 691d731503b88..d665af5747c60 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx @@ -252,6 +252,7 @@ void CheckResidSpec::process() auto& accum = slots[0]; #endif auto& resTrack = accum.emplace_back(); + resTrack.gid = vid; if (!processITSTrack(itsTrack, pve, resTrack)) { accum.pop_back(); continue; From 587eb9487ae816790b3c4f7fe7db3fd22e9a8d85 Mon Sep 17 00:00:00 2001 From: Ernst Hellbar Date: Wed, 21 Jan 2026 09:48:37 +0100 Subject: [PATCH 106/234] TRD: add missing OutputSpec in trd-pulseheight device --- Detectors/TRD/workflow/include/TRDWorkflow/TRDPulseHeightSpec.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDPulseHeightSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDPulseHeightSpec.h index 3cfbb16644e54..be00e478608ec 100644 --- a/Detectors/TRD/workflow/include/TRDWorkflow/TRDPulseHeightSpec.h +++ b/Detectors/TRD/workflow/include/TRDWorkflow/TRDPulseHeightSpec.h @@ -69,6 +69,7 @@ class PuseHeightDevice : public o2::framework::Task mPulseHeight->reset(); mPulseHeight->process(); pc.outputs().snapshot(Output{"TRD", "PULSEHEIGHT", 0}, mPulseHeight->getPHData()); + pc.outputs().snapshot(Output{"TRD", "PULSEHEIGHTHD", 0}, mPulseHeight->getPHDataHD()); if (pc.transitionState() == TransitionHandlingState::Requested) { LOG(info) << "Run stop requested, finalizing"; mRunStopRequested = true; @@ -103,6 +104,7 @@ DataProcessorSpec getTRDPulseHeightSpec(GID::mask_t src, bool digitsFromReader) std::vector outputs; outputs.emplace_back(o2::header::gDataOriginTRD, "PULSEHEIGHT", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTRD, "PULSEHEIGHTHD", 0, Lifetime::Timeframe); bool isTPCavailable = false; if (GID::includesSource(GID::Source::ITSTPC, src)) { From 397e0194d0ab4d02f61c75ca40eb024703208478 Mon Sep 17 00:00:00 2001 From: Barthelemy Date: Wed, 21 Jan 2026 16:55:50 +0100 Subject: [PATCH 107/234] [O2-6625] Fix the missing filename in the CCDb --- CCDB/src/CcdbApi.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CCDB/src/CcdbApi.cxx b/CCDB/src/CcdbApi.cxx index f083d97b533df..42bc13904bf61 100644 --- a/CCDB/src/CcdbApi.cxx +++ b/CCDB/src/CcdbApi.cxx @@ -416,7 +416,7 @@ int CcdbApi::storeAsBinaryFile(const char* buffer, size_t size, const std::strin auto mime = curl_mime_init(curl); auto field = curl_mime_addpart(mime); curl_mime_name(field, "send"); - if (filename.empty()) { + if (!filename.empty()) { curl_mime_filedata(field, filename.c_str()); } if (buffer != nullptr && size > 0) { From 078eb5d8b2ed24527f7488e5b8fbae866820a46d Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 22 Jan 2026 15:58:36 +0100 Subject: [PATCH 108/234] Revert "DPL Analysis: Use dangling edges context in more places (#14953)" This reverts commit c990996954857d60b683fadc3bc037f055276c5d. --- .../AnalysisSupport/src/AODWriterHelpers.cxx | 21 +++---- .../CCDBSupport/src/AnalysisCCDBHelpers.cxx | 59 +++++++++---------- .../CCDBSupport/src/AnalysisCCDBHelpers.h | 2 +- .../Core/include/Framework/AnalysisTask.h | 4 +- Framework/Core/src/AnalysisSupportHelpers.cxx | 4 +- 5 files changed, 45 insertions(+), 45 deletions(-) diff --git a/Framework/AnalysisSupport/src/AODWriterHelpers.cxx b/Framework/AnalysisSupport/src/AODWriterHelpers.cxx index b76ffca13977e..d868b7498fb76 100644 --- a/Framework/AnalysisSupport/src/AODWriterHelpers.cxx +++ b/Framework/AnalysisSupport/src/AODWriterHelpers.cxx @@ -62,13 +62,13 @@ const static std::unordered_map ROOTfileNa AlgorithmSpec AODWriterHelpers::getOutputTTreeWriter(ConfigContext const& ctx) { + auto& ac = ctx.services().get(); auto dod = AnalysisSupportHelpers::getDataOutputDirector(ctx); int compressionLevel = 505; if (ctx.options().hasOption("aod-writer-compression")) { compressionLevel = ctx.options().get("aod-writer-compression"); } - return AlgorithmSpec{[dod, compressionLevel](InitContext& ic) -> std::function { - auto outputInputs = ic.services().get().outputsInputsAOD; + return AlgorithmSpec{[dod, outputInputs = ac.outputsInputsAOD, compressionLevel](InitContext& ic) -> std::function { LOGP(debug, "======== getGlobalAODSink::Init =========="); // find out if any table needs to be saved @@ -241,13 +241,14 @@ AlgorithmSpec AODWriterHelpers::getOutputTTreeWriter(ConfigContext const& ctx) }; } -AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& /*ctx*/) +AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& ctx) { - return AlgorithmSpec{[](InitContext& ic) -> std::function { - using namespace monitoring; - auto& dec = ic.services().get(); - auto tskmap = dec.outTskMap; - auto objmap = dec.outObjHistMap; + using namespace monitoring; + auto& ac = ctx.services().get(); + auto tskmap = ac.outTskMap; + auto objmap = ac.outObjHistMap; + + return AlgorithmSpec{[objmap, tskmap](InitContext& ic) -> std::function { auto& callbacks = ic.services().get(); auto inputObjects = std::make_shared>>(); @@ -277,7 +278,7 @@ AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& /*ct callbacks.set(endofdatacb); return [inputObjects, objmap, tskmap](ProcessingContext& pc) mutable -> void { - auto mergePart = [&inputObjects, &objmap, &tskmap](DataRef const& ref) { + auto mergePart = [&inputObjects, &objmap, &tskmap, &pc](DataRef const& ref) { O2_SIGNPOST_ID_GENERATE(hid, histogram_registry); O2_SIGNPOST_START(histogram_registry, hid, "mergePart", "Merging histogram"); if (!ref.header) { @@ -473,7 +474,7 @@ AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& /*ct }; O2_SIGNPOST_ID_GENERATE(rid, histogram_registry); O2_SIGNPOST_START(histogram_registry, rid, "processParts", "Start merging %zu parts received together.", pc.inputs().getNofParts(0)); - for (auto pi = 0U; pi < pc.inputs().getNofParts(0); ++pi) { + for (int pi = 0; pi < pc.inputs().getNofParts(0); ++pi) { mergePart(pc.inputs().get("x", pi)); } O2_SIGNPOST_END(histogram_registry, rid, "processParts", "Done histograms in multipart message."); diff --git a/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx b/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx index 413adfddecf04..9ec911518f754 100644 --- a/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx +++ b/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx @@ -67,39 +67,38 @@ void fillValidRoutes(CCDBFetcherHelper& helper, std::vector(); - std::vector> schemas; - auto schemaMetadata = std::make_shared(); + auto& ac = ctx.services().get(); + std::vector> schemas; + auto schemaMetadata = std::make_shared(); - for (auto& input : dec.analysisCCDBInputs) { - std::vector> fields; - schemaMetadata->Append("outputRoute", DataSpecUtils::describe(input)); - schemaMetadata->Append("outputBinding", input.binding); + for (auto& input : ac.analysisCCDBInputs) { + std::vector> fields; + schemaMetadata->Append("outputRoute", DataSpecUtils::describe(input)); + schemaMetadata->Append("outputBinding", input.binding); - for (auto& m : input.metadata) { - // Save the list of input tables - if (m.name.starts_with("input:")) { - auto name = m.name.substr(6); - schemaMetadata->Append("sourceTable", name); - schemaMetadata->Append("sourceMatcher", DataSpecUtils::describe(std::get(DataSpecUtils::fromMetadataString(m.defaultValue.get()).matcher))); - continue; - } - // Ignore the non ccdb: entries - if (!m.name.starts_with("ccdb:")) { - continue; - } - // Create the schema of the output - auto metadata = std::make_shared(); - metadata->Append("url", m.defaultValue.asString()); - auto columnName = m.name.substr(strlen("ccdb:")); - fields.emplace_back(std::make_shared(columnName, arrow::binary_view(), false, metadata)); + for (auto& m : input.metadata) { + // Save the list of input tables + if (m.name.starts_with("input:")) { + auto name = m.name.substr(6); + schemaMetadata->Append("sourceTable", name); + schemaMetadata->Append("sourceMatcher", DataSpecUtils::describe(std::get(DataSpecUtils::fromMetadataString(m.defaultValue.get()).matcher))); + continue; + } + // Ignore the non ccdb: entries + if (!m.name.starts_with("ccdb:")) { + continue; } - schemas.emplace_back(std::make_shared(fields, schemaMetadata)); + // Create the schema of the output + auto metadata = std::make_shared(); + metadata->Append("url", m.defaultValue.asString()); + auto columnName = m.name.substr(strlen("ccdb:")); + fields.emplace_back(std::make_shared(columnName, arrow::binary_view(), false, metadata)); } - + schemas.emplace_back(std::make_shared(fields, schemaMetadata)); + } + return adaptStateful([schemas](CallbackService& callbacks, ConfigParamRegistry const& options, DeviceSpec const& spec) { std::shared_ptr helper = std::make_shared(); CCDBFetcherHelper::initialiseHelper(*helper, options); std::unordered_map bindings; @@ -130,11 +129,11 @@ AlgorithmSpec AnalysisCCDBHelpers::fetchFromCCDB(ConfigContext const& /*ctx*/) int outputRouteIndex = bindings.at(outRouteDesc); auto& spec = helper->routes[outputRouteIndex].matcher; std::vector> builders; - for (auto const& _ : schema->fields()) { + for (auto& _ : schema->fields()) { builders.emplace_back(std::make_shared()); } - for (auto ci = 0; ci < timestampColumn->num_chunks(); ++ci) { + for (size_t ci = 0; ci < timestampColumn->num_chunks(); ++ci) { std::shared_ptr chunk = timestampColumn->chunk(ci); auto const* timestamps = chunk->data()->GetValuesSafe(1); diff --git a/Framework/CCDBSupport/src/AnalysisCCDBHelpers.h b/Framework/CCDBSupport/src/AnalysisCCDBHelpers.h index 3be2138bd2b5c..f8175034da0ba 100644 --- a/Framework/CCDBSupport/src/AnalysisCCDBHelpers.h +++ b/Framework/CCDBSupport/src/AnalysisCCDBHelpers.h @@ -17,7 +17,7 @@ namespace o2::framework { struct AnalysisCCDBHelpers { - static AlgorithmSpec fetchFromCCDB(ConfigContext const&); + static AlgorithmSpec fetchFromCCDB(ConfigContext const& ctx); }; } // namespace o2::framework diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index 4f8a9e719e4b9..c50b5358990de 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -521,7 +521,7 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) std::vector expressionInfos; /// make sure options and configurables are set before expression infos are created - homogeneous_apply_refs([&options](auto& element) { return analysis_task_parsers::appendOption(options, element); }, *task.get()); + homogeneous_apply_refs([&options, &hash](auto& element) { return analysis_task_parsers::appendOption(options, element); }, *task.get()); /// extract conditions and append them as inputs homogeneous_apply_refs([&inputs](auto& element) { return analysis_task_parsers::appendCondition(inputs, element); }, *task.get()); @@ -620,7 +620,7 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) } // reset pre-slice for the next dataframe auto slices = pc.services().get(); - homogeneous_apply_refs([&slices](auto& element) { + homogeneous_apply_refs([&pc, &slices](auto& element) { return analysis_task_parsers::updateSliceInfo(element, slices); }, *(task.get())); diff --git a/Framework/Core/src/AnalysisSupportHelpers.cxx b/Framework/Core/src/AnalysisSupportHelpers.cxx index 7edf9a2d8d27f..15b56f9afbff5 100644 --- a/Framework/Core/src/AnalysisSupportHelpers.cxx +++ b/Framework/Core/src/AnalysisSupportHelpers.cxx @@ -98,7 +98,7 @@ std::shared_ptr AnalysisSupportHelpers::getDataOutputDirecto if (!keepString.empty()) { dod->reset(); std::string d("dangling"); - if (d.starts_with(keepString) == 0) { + if (d.find(keepString) == 0) { // use the dangling outputs std::vector danglingOutputs; for (auto ii = 0u; ii < OutputsInputs.size(); ii++) { @@ -144,7 +144,7 @@ void AnalysisSupportHelpers::addMissingOutputsToSpawner(std::vector sinks::append_to{publisher.outputs}; // append them to the publisher outputs std::vector additionalInputs; - for (auto const& input : requestedSpecials | views::filter_not_matching(providedSpecials)) { + for (auto& input : requestedSpecials | views::filter_not_matching(providedSpecials)) { input.metadata | views::filter_string_params_with("input:") | views::params_to_input_specs() | From 538f355832f7b5e353704b09c123dd603521e7df Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 22 Jan 2026 10:09:02 +0100 Subject: [PATCH 109/234] DPL: do not do the new early forwarding for some of the data --- Framework/Core/src/DataProcessingDevice.cxx | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index fb54af9402079..3eaab36fb7908 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -1054,11 +1054,22 @@ void DataProcessingDevice::fillContext(DataProcessorContext& context, DeviceCont } auto decideEarlyForward = [&context, &deviceContext, &spec, this]() -> ForwardPolicy { - //ForwardPolicy defaultEarlyForwardPolicy = getenv("DPL_OLD_EARLY_FORWARD") ? ForwardPolicy::AtCompletionPolicySatisified : ForwardPolicy::AtInjection; - // Make the new policy optional until we handle some of the corner cases - // with custom policies which expect the early forward to happen only when - // all the data is available, like in the TPC case. - ForwardPolicy defaultEarlyForwardPolicy = getenv("DPL_NEW_EARLY_FORWARD") ? ForwardPolicy::AtInjection : ForwardPolicy::AtCompletionPolicySatisified; + ForwardPolicy defaultEarlyForwardPolicy = getenv("DPL_OLD_EARLY_FORWARD") ? ForwardPolicy::AtCompletionPolicySatisified : ForwardPolicy::AtInjection; + // FIXME: try again with the new policy by default. + // + // Make the new policy optional until we handle some of the corner cases + // with custom policies which expect the early forward to happen only when + // all the data is available, like in the TPC case. + // ForwardPolicy defaultEarlyForwardPolicy = getenv("DPL_NEW_EARLY_FORWARD") ? ForwardPolicy::AtInjection : ForwardPolicy::AtCompletionPolicySatisified; + for (auto& forward : spec.forwards) { + if (DataSpecUtils::match(forward.matcher, ConcreteDataTypeMatcher{"TPC", "DIGITSMCTR"}) || + DataSpecUtils::match(forward.matcher, ConcreteDataTypeMatcher{"TPC", "CLNATIVEMCLBL"}) || + DataSpecUtils::match(forward.matcher, ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, "DIGITS"}) || + DataSpecUtils::match(forward.matcher, ConcreteDataTypeMatcher{o2::header::gDataOriginTPC, "CLUSTERNATIVE"})) { + defaultEarlyForwardPolicy = ForwardPolicy::AtCompletionPolicySatisified; + break; + } + } /// We must make sure there is no optional /// if we want to optimize the forwarding From 5376bb861a3a935a2a8211917d6d2e52e51c535e Mon Sep 17 00:00:00 2001 From: shahoian Date: Fri, 23 Jan 2026 17:01:44 +0100 Subject: [PATCH 110/234] PVertexer::refitVertexFull for refitting with different geom. In in case the residuals monitoring is running with geometry different from the one used for initial reconstruction pass a --configKeyValues option for the vertex refit as: ;pvertexer.useMeanVertexConstraint=false;pvertexer.iniScale2=100;pvertexer.acceptableScale2=10.; It will be used by the PVertexer::refitVertexFull. --- .../GlobalTrackingStudy/CheckResidConfig.h | 5 ++- .../study/src/CheckResid.cxx | 40 ++++++++++++------- .../include/DetectorsVertexing/PVertexer.h | 4 +- Detectors/Vertexing/src/PVertexer.cxx | 31 ++++++++++++++ 4 files changed, 62 insertions(+), 18 deletions(-) diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidConfig.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidConfig.h index 53dffeed7ad69..2a07eaf87930f 100644 --- a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidConfig.h +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidConfig.h @@ -26,11 +26,14 @@ struct CheckResidConfig : o2::conf::ConfigurableParamHelper { bool pvcontribOnly = true; bool addPVAsCluster = true; - bool refitPV = true; bool useStableRef = true; bool doIBOB = true; bool doResid = true; + bool refitPV = true; + float refitPVMV = false; + float refitPVIniScale = 100.f; + O2ParamDef(CheckResidConfig, "checkresid"); }; } // namespace o2::checkresid diff --git a/Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx b/Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx index d665af5747c60..e6584a7055446 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx @@ -38,14 +38,17 @@ #include "CommonUtils/TreeStreamRedirector.h" #include "ReconstructionDataFormats/VtxTrackRef.h" #include "DetectorsVertexing/PVertexer.h" - #ifdef WITH_OPENMP #include #endif +// Attention: in case the residuals are checked with geometry different from the one used for initial reconstruction, +// pass a --configKeyValues option for vertex refit as: +// ;pvertexer.useMeanVertexConstraint=false;pvertexer.iniScale2=100;pvertexer.acceptableScale2=10.; +// In any case, it is better to pass ;pvertexer.useMeanVertexConstraint=false; + namespace o2::checkresid { - using namespace o2::framework; using DetID = o2::detectors::DetID; using DataRequest = o2::globaltracking::DataRequest; @@ -83,6 +86,7 @@ class CheckResidSpec : public Task o2::globaltracking::RecoContainer* mRecoData = nullptr; int mNThreads = 1; + bool mMeanVertexUpdated = false; float mITSROFrameLengthMUS = 0.f; o2::dataformats::MeanVertexObject mMeanVtx{}; std::vector> mITSClustersArray; ///< ITS clusters created in run() method from compact clusters @@ -131,6 +135,7 @@ void CheckResidSpec::updateTimeDependentParams(ProcessingContext& pc) // mTPCCorrMapsLoader.extractCCDBInputs(pc); static bool initOnceDone = false; if (!initOnceDone) { // this params need to be queried only once + const auto& params = o2::checkresid::CheckResidConfig::Instance(); initOnceDone = true; // Note: reading of the ITS AlpideParam needed for ITS timing is done by the RecoContainer auto grp = o2::base::GRPGeomHelper::instance().getGRPECS(); @@ -142,9 +147,13 @@ void CheckResidSpec::updateTimeDependentParams(ProcessingContext& pc) } auto geom = o2::its::GeometryTGeo::Instance(); geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G, o2::math_utils::TransformType::T2G)); - o2::conf::ConfigurableParam::updateFromString("pvertexer.useMeanVertexConstraint=false"); + o2::conf::ConfigurableParam::updateFromString("pvertexer.useTimeInChi2=false;"); mVertexer.init(); } + if (mMeanVertexUpdated) { + mMeanVertexUpdated = false; + mVertexer.initMeanVertexConstraint(); + } bool updateMaps = false; /* if (mTPCCorrMapsLoader.isUpdated()) { @@ -200,6 +209,7 @@ void CheckResidSpec::process() } nvGood++; if (params.refitPV) { + LOGP(debug, "Refitting PV#{} of {} tracks", iv, pve.getNContributors()); auto tStartPVF = std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); bool res = refitPV(pve, iv); pvFitDuration += std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count() - tStartPVF; @@ -315,6 +325,7 @@ bool CheckResidSpec::processITSTrack(const o2::its::TrackITS& iTrack, const o2:: resTrack.points.clear(); if (!prop->propagateToDCA(pv, trFitOut, bz)) { + LOGP(debug, "Failed to propagateToDCA, {}", trFitOut.asString()); return false; } float cosAlp, sinAlp; @@ -418,7 +429,7 @@ bool CheckResidSpec::refitPV(o2::dataformats::PrimaryVertex& pv, int vid) std::vector tracks; std::vector useTrack; std::vector gidsITS; - int ntr = pv.getNContributors(); + int ntr = pv.getNContributors(), ntrIni = ntr; tracks.reserve(ntr); useTrack.reserve(ntr); gidsITS.reserve(ntr); @@ -447,20 +458,18 @@ bool CheckResidSpec::refitPV(o2::dataformats::PrimaryVertex& pv, int vid) ntr++; } if (ntr < params.minPVContributors || !mVertexer.prepareVertexRefit(tracks, pv)) { + LOGP(warn, "Abandon vertex refit: NcontribNew = {} vs NcontribOld = {}", ntr, ntrIni); return false; } - // readjust vertexZ - const auto& pool = mVertexer.getTracksPool(); - float zUpd = 0; - for (const auto& t : pool) { - zUpd += t.z; - } - if (pool.size()) { - pv.setZ(zUpd / pool.size()); - mVertexer.prepareVertexRefit(tracks, pv); + LOGP(debug, "Original vtx: Nc:{} {}, chi2={}", pv.getNContributors(), pv.asString(), pv.getChi2()); + auto pvSave = pv; + pv = mVertexer.refitVertexFull(useTrack, pv); + LOGP(debug, "Refitted vtx: Nc:{} {}, chi2={}", ntr, pv.asString(), pv.getChi2()); + if (pv.getChi2() < 0.f) { + LOGP(warn, "Failed to refit PV {}", pvSave.asString()); + return false; } - pv = mVertexer.refitVertex(useTrack, pv); - return pv.getChi2() > 0.f; + return true; } bool CheckResidSpec::refitITStrack(o2::track::TrackParCov& track, GTrackID gid) @@ -515,6 +524,7 @@ void CheckResidSpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) if (matcher == ConcreteDataMatcher("GLO", "MEANVERTEX", 0)) { LOG(info) << "Imposing new MeanVertex: " << ((const o2::dataformats::MeanVertexObject*)obj)->asString(); mMeanVtx = *(const o2::dataformats::MeanVertexObject*)obj; + mMeanVertexUpdated = true; return; } if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) { diff --git a/Detectors/Vertexing/include/DetectorsVertexing/PVertexer.h b/Detectors/Vertexing/include/DetectorsVertexing/PVertexer.h index 9967cbfcd5642..c06c2119b0cd1 100644 --- a/Detectors/Vertexing/include/DetectorsVertexing/PVertexer.h +++ b/Detectors/Vertexing/include/DetectorsVertexing/PVertexer.h @@ -113,7 +113,7 @@ class PVertexer bool prepareVertexRefit(const TR& tracks, const o2d::VertexBase& vtxSeed); PVertex refitVertex(const std::vector useTrack, const o2d::VertexBase& vtxSeed); - + PVertex refitVertexFull(const std::vector useTrack, const o2d::VertexBase& vtxSeed); auto getNTZClusters() const { return mNTZClustersIni; } auto getTotTrials() const { return mTotTrials; } auto getMaxTrialsPerCluster() const { return mMaxTrialPerCluster; } @@ -135,6 +135,7 @@ class PVertexer void setPoolDumpDirectory(const std::string& d) { mPoolDumpDirectory = d; } void printInpuTracksStatus(const VertexingInput& input) const; + void initMeanVertexConstraint(); private: static constexpr int DBS_UNDEF = -2, DBS_NOISE = -1, DBS_INCHECK = -10; @@ -152,7 +153,6 @@ class PVertexer FitStatus evalIterations(VertexSeed& vtxSeed, PVertex& vtx) const; TimeEst timeEstimate(const VertexingInput& input) const; float findZSeedHistoPeak() const; - void initMeanVertexConstraint(); void applyConstraint(VertexSeed& vtxSeed) const; bool upscaleSigma(VertexSeed& vtxSeed) const; bool relateTrackToMeanVertex(o2::track::TrackParCov& trc, float vtxErr2); diff --git a/Detectors/Vertexing/src/PVertexer.cxx b/Detectors/Vertexing/src/PVertexer.cxx index 5fea1943ac762..10e504bba0772 100644 --- a/Detectors/Vertexing/src/PVertexer.cxx +++ b/Detectors/Vertexing/src/PVertexer.cxx @@ -1333,6 +1333,37 @@ PVertex PVertexer::refitVertex(const std::vector useTrack, const o2d::Vert return vtxRes; } +//______________________________________________ +PVertex PVertexer::refitVertexFull(const std::vector useTrack, const o2d::VertexBase& vtxSeed) +{ + // Use this method if because of e.g. different alingnment the new vertex is supposed to be shifted from the original one. + // Refit the tracks prepared by the successful prepareVertexRefit, possible skipping those tracks wich have useTrack value false + // (useTrack is ignored if empty). + // The vtxSeed is the originally found vertex, assumed to be the same original PV used for the prepareVertexRefit. + // Refitted PrimaryVertex is returned, negative chi2 means failure of the refit. + // ATTENTION: only the position is refitted, the vertex time and IRMin/IRMax info is dummy. + + if (vtxSeed != mVtxRefitOrig) { + throw std::runtime_error("refitVertex must be preceded by successful prepareVertexRefit"); + } + VertexingInput inp; + inp.scaleSigma2 = mPVParams->iniScale2; + inp.idRange = gsl::span(mRefitTrackIDs); + if (useTrack.size()) { + for (uint32_t i = 0; i < mTracksPool.size(); i++) { + mTracksPool[i].vtxID = useTrack[mTracksPool[i].entry] ? TrackVF::kNoVtx : TrackVF::kDiscarded; + } + } + PVertex vtxRes{}; + vtxRes.VertexBase::operator=(vtxSeed); + if (findVertex(inp, vtxRes)) { + vtxRes.setTimeStamp({0.f, -1.}); // time is not refitter + } else { + vtxRes.setChi2(-1.); + } + return vtxRes; +} + //______________________________________________ void PVertexer::printInpuTracksStatus(const VertexingInput& input) const { From 5b572ed12a5b3ca085a18d9ece546a84a98c3c30 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Fri, 11 Jul 2025 14:01:38 +0200 Subject: [PATCH 111/234] ITSMFT: staggered digitization Signed-off-by: Felix Schlepper --- .../Detectors/ITSMFT/common/src/ROFRecord.cxx | 14 +- .../ITS/base/include/ITSBase/GeometryTGeo.h | 8 +- .../MFT/base/include/MFTBase/GeometryTGeo.h | 6 +- .../base/include/ITSMFTBase/DPLAlpideParam.h | 41 +- .../base/include/ITSMFTBase/GeometryTGeo.h | 5 +- .../include/ITSMFTSimulation/DigiParams.h | 45 +- .../include/ITSMFTSimulation/Digitizer.h | 24 +- .../common/simulation/src/DigiParams.cxx | 44 +- .../common/simulation/src/Digitizer.cxx | 98 ++--- .../include/ITSMFTWorkflow/DigitReaderSpec.h | 54 +-- .../common/workflow/src/DigitReaderSpec.cxx | 223 +++++----- .../common/workflow/src/DigitWriterSpec.cxx | 84 +++- .../src/ITSMFTDigitizerSpec.cxx | 413 ++++++++++-------- 13 files changed, 614 insertions(+), 445 deletions(-) diff --git a/DataFormats/Detectors/ITSMFT/common/src/ROFRecord.cxx b/DataFormats/Detectors/ITSMFT/common/src/ROFRecord.cxx index 83b46f8798fc9..8dbde0d580efc 100644 --- a/DataFormats/Detectors/ITSMFT/common/src/ROFRecord.cxx +++ b/DataFormats/Detectors/ITSMFT/common/src/ROFRecord.cxx @@ -9,20 +9,22 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "DataFormatsITSMFT/ROFRecord.h" #include -#include "fmt/format.h" +#include + +#include "DataFormatsITSMFT/ROFRecord.h" +#include "Framework/Logger.h" using namespace o2::itsmft; std::string ROFRecord::asString() const { - return fmt::format("ROF: {} | {} entries starting from {}", mROFrame, getNEntries(), getFirstEntry()); + return std::format("ROF: {} | {} entries starting from {} | IR: {}", mROFrame, getNEntries(), getFirstEntry(), mBCData.asString()); } void ROFRecord::print() const { - std::cout << this << "\n\t" << mBCData << std::endl; + LOG(info) << asString(); } std::ostream& operator<<(std::ostream& stream, ROFRecord const& rec) @@ -33,12 +35,12 @@ std::ostream& operator<<(std::ostream& stream, ROFRecord const& rec) std::string MC2ROFRecord::asString() const { - return fmt::format("MCEventID: {} ROFs: {}-{} Entry in ROFRecords: {}", eventRecordID, minROF, maxROF, rofRecordID); + return std::format("MCEventID: {} ROFs: {}-{} Entry in ROFRecords: {}", eventRecordID, minROF, maxROF, rofRecordID); } void MC2ROFRecord::print() const { - std::cout << this << std::endl; + LOG(info) << asString(); } std::ostream& operator<<(std::ostream& stream, MC2ROFRecord const& rec) diff --git a/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h b/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h index 934c927ac3059..e236c898851f5 100644 --- a/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h +++ b/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h @@ -176,7 +176,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo bool getChipId(int index, int& lay, int& hba, int& sta, int& ssta, int& mod, int& chip) const; /// Get chip layer, from 0 - int getLayer(int index) const; + int getLayer(int index) const final; /// Get chip half barrel, from 0 int getHalfBarrel(int index) const; @@ -216,7 +216,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo return getSymbolicName(getChipIndex(lay, hba, sta, det)); } - /// Get the transformation matrix for a given chip (NOT A SENSOR!!!) 'index' by quering the TGeoManager + /// Get the transformation matrix for a given chip (NOT A SENSOR!!!) 'index' by querying the TGeoManager TGeoHMatrix* getMatrix(int index) const { return o2::base::GeometryManager::getMatrix(getDetID(), index); } TGeoHMatrix* getMatrix(int lay, int hba, int sta, int sens) const { return getMatrix(getChipIndex(lay, hba, sta, sens)); } bool getOriginalMatrix(int index, TGeoHMatrix& m) const @@ -336,7 +336,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo TString getMatrixPath(int index) const; /// Get the transformation matrix of the SENSOR (not necessary the same as the chip) - /// for a given chip 'index' by quering the TGeoManager + /// for a given chip 'index' by querying the TGeoManager TGeoHMatrix* extractMatrixSensor(int index) const; // create matrix for transformation from sensor local frame to global one @@ -407,7 +407,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo std::vector mNumberOfChipsPerStave; ///< number of chips per stave std::vector mNumberOfChipsPerHalfBarrel; ///< number of chips per halfbarrel std::vector mNumberOfChipsPerLayer; ///< number of chips per stave - std::vector mLastChipIndex; ///< max ID of the detctor in the layer + std::vector mLastChipIndex; ///< max ID of the detector in the layer std::array mIsLayerITS3; ///< flag with the information of the ITS version (ITS2 or ITS3) std::array mLayerToWrapper; ///< Layer to wrapper correspondence diff --git a/Detectors/ITSMFT/MFT/base/include/MFTBase/GeometryTGeo.h b/Detectors/ITSMFT/MFT/base/include/MFTBase/GeometryTGeo.h index 503e8332c4cf5..20b5407d614c5 100644 --- a/Detectors/ITSMFT/MFT/base/include/MFTBase/GeometryTGeo.h +++ b/Detectors/ITSMFT/MFT/base/include/MFTBase/GeometryTGeo.h @@ -95,7 +95,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo Int_t getSensorIndex(Int_t half, Int_t disk, Int_t ladder, Int_t sensor) const; /// get layer index (0:9) from the chip index - Int_t getLayer(Int_t index) const; + Int_t getLayer(Int_t index) const final; /// This routine computes the half, disk, ladder and sensor number /// given the sensor index number @@ -122,7 +122,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo { return extractNumberOfDisks(half); } - /// Returns the number of halfs MFT + /// Returns the number of halves MFT Int_t getNumberOfHalfs() { return extractNumberOfHalves(); @@ -181,7 +181,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo Int_t extractVolumeCopy(const Char_t* name, const Char_t* prefix) const; /// Get the transformation matrix of the sensor [...] - /// for a given sensor 'index' by quering the TGeoManager + /// for a given sensor 'index' by querying the TGeoManager TGeoHMatrix* extractMatrixSensor(Int_t index) const; // Create matrix for transformation from sensor local frame to global one diff --git a/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h b/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h index bc3b3dbde53b0..de39bed299634 100644 --- a/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h +++ b/Detectors/ITSMFT/common/base/include/ITSMFTBase/DPLAlpideParam.h @@ -26,17 +26,44 @@ constexpr float DEFStrobeDelay = o2::constants::lhc::LHCBunchSpacingNS * 4; // ~ template struct DPLAlpideParam : public o2::conf::ConfigurableParamHelper> { + static constexpr int getNLayers() + { + return N == o2::detectors::DetID::ITS ? 7 : 10; + } static constexpr std::string_view getParamName() { return N == o2::detectors::DetID::ITS ? ParamName[0] : ParamName[1]; } - int roFrameLengthInBC = DEFROFLengthBC(); ///< ROF length in BC for continuos mode - float roFrameLengthTrig = DEFROFLengthTrig(); ///< length of RO frame in ns for triggered mode - float strobeDelay = DEFStrobeDelay; ///< strobe start (in ns) wrt ROF start - float strobeLengthCont = -1.; ///< if < 0, full ROF length - delay - float strobeLengthTrig = 100.; ///< length of the strobe in ns (sig. over threshold checked in this window only) - int roFrameBiasInBC = DEFROFBiasInBC(); ///< bias of the start of ROF wrt orbit start: t_irof = (irof*roFrameLengthInBC + roFrameBiasInBC)*BClengthMUS + + int roFrameLengthInBC = DEFROFLengthBC(); ///< ROF length in BC for continuous mode + float roFrameLengthTrig = DEFROFLengthTrig(); ///< length of RO frame in ns for triggered mode + float strobeDelay = DEFStrobeDelay; ///< strobe start (in ns) wrt ROF start + float strobeLengthCont = -1.; ///< if < 0, full ROF length - delay + float strobeLengthTrig = 100.; ///< length of the strobe in ns (sig. over threshold checked in this window only) + int roFrameBiasInBC = DEFROFBiasInBC(); ///< bias of the start of ROF wrt orbit start: t_irof = (irof*roFrameLengthInBC + roFrameBiasInBC)*BClengthMUS + int roFrameLayerLengthInBC[getNLayers()] = {}; ///< staggering ROF length in BC for continuous mode per layer + int roFrameLayerBiasInBC[getNLayers()] = {}; ///< staggering ROF bias in BC for continuous mode per layer + int roFrameLayerDelayInBC[getNLayers()] = {}; ///< staggering ROF delay in BC for continuous mode per layer + + static constexpr bool supportsStaggering() noexcept { return (N == o2::detectors::DetID::ITS) ? false : false; } + // test if staggering is on + bool withStaggering() const noexcept + { + if constexpr (!supportsStaggering()) { + return false; + } + for (int i{0}; i < getNLayers(); ++i) { + if (roFrameLayerLengthInBC[i] != 0) { + return true; + } + } + return false; + } + // get ROF length for any layer + int getROFLengthInBC(int layer) const noexcept { return (withStaggering()) ? roFrameLayerLengthInBC[layer] : roFrameLengthInBC; } + int getROFBiasInBC(int layer) const noexcept { return (withStaggering()) ? roFrameLayerBiasInBC[layer] : roFrameBiasInBC; } + int getROFDelayInBC(int layer) const noexcept { return (withStaggering()) ? roFrameLayerDelayInBC[layer] : 0; } // boilerplate stuff + make principal key O2ParamDef(DPLAlpideParam, getParamName().data()); @@ -46,7 +73,7 @@ struct DPLAlpideParam : public o2::conf::ConfigurableParamHelper +#include #include -#include +#include "ITSMFTSimulation/AlpideSignalTrapezoid.h" #include "ITSMFTBase/DPLAlpideParam.h" //////////////////////////////////////////////////////////// @@ -51,24 +53,24 @@ class DigiParams void setContinuous(bool v) { mIsContinuous = v; } bool isContinuous() const { return mIsContinuous; } - int getROFrameLengthInBC() const { return mROFrameLengthInBC; } - void setROFrameLengthInBC(int n) { mROFrameLengthInBC = n; } + int getROFrameLengthInBC(int layer = -1) const { return layer < 0 ? mROFrameLengthInBC : mROFrameLayerLengthInBC[layer]; } + void setROFrameLengthInBC(int n, int layer = -1) { layer < 0 ? mROFrameLengthInBC = n : mROFrameLayerLengthInBC[layer] = n; } - void setROFrameLength(float ns); - float getROFrameLength() const { return mROFrameLength; } - float getROFrameLengthInv() const { return mROFrameLengthInv; } + void setROFrameLength(float ns, int layer = -1); + float getROFrameLength(int layer = -1) const { return layer < 0 ? mROFrameLength : mROFrameLayerLength[layer]; } + float getROFrameLengthInv(int layer = -1) const { return layer < 0 ? mROFrameLengthInv : mROFrameLayerLengthInv[layer]; } void setStrobeDelay(float ns) { mStrobeDelay = ns; } - float getStrobeDelay() const { return mStrobeDelay; } + float getStrobeDelay(int layer = -1) const { return layer < 0 ? mStrobeDelay : mStrobeLayerDelay[layer]; } void setStrobeLength(float ns) { mStrobeLength = ns; } - float getStrobeLength() const { return mStrobeLength; } + float getStrobeLength(int layer = -1) const { return layer < 0 ? mStrobeLength : mStrobeLayerLength[layer]; } void setTimeOffset(double sec) { mTimeOffset = sec; } double getTimeOffset() const { return mTimeOffset; } - void setROFrameBiasInBC(int n) { mROFrameBiasInBC = n; } - int getROFrameBiasInBC() const { return mROFrameBiasInBC; } + void setROFrameBiasInBC(int n, int layer = -1) { layer < 0 ? mROFrameBiasInBC = n : mROFrameLayerBiasInBC[layer] = n; } + int getROFrameBiasInBC(int layer = -1) const { return layer < 0 ? mROFrameBiasInBC : mROFrameLayerBiasInBC[layer]; } void setChargeThreshold(int v, float frac2Account = 0.1); void setNSimSteps(int v); @@ -96,13 +98,19 @@ class DigiParams const SignalShape& getSignalShape() const { return mSignalShape; } SignalShape& getSignalShape() { return (SignalShape&)mSignalShape; } + bool withStaggering() const noexcept { return !mROFrameLayerLength.empty(); } + void addROFrameLayerLengthInBC(int len) { mROFrameLayerLengthInBC.push_back(len); } + void addROFrameLayerBiasInBC(int len) { mROFrameLayerBiasInBC.push_back(len); } + void addStrobeLength(float ns) { mStrobeLayerLength.push_back(ns); } + void addStrobeDelay(float ns) { mStrobeLayerDelay.push_back(ns); } + virtual void print() const; private: static constexpr double infTime = 1e99; bool mIsContinuous = false; ///< flag for continuous simulation float mNoisePerPixel = 1.e-8; ///< ALPIDE Noise per chip - int mROFrameLengthInBC = 0; ///< ROF length in BC for continuos mode + int mROFrameLengthInBC = 0; ///< ROF length in BC for continuous mode float mROFrameLength = 0; ///< length of RO frame in ns float mStrobeDelay = 0.; ///< strobe start (in ns) wrt ROF start float mStrobeLength = 0; ///< length of the strobe in ns (sig. over threshold checked in this window only) @@ -115,17 +123,24 @@ class DigiParams float mVbb = 0.0; ///< back bias absolute value for MFT (in Volt) float mIBVbb = 0.0; ///< back bias absolute value for ITS Inner Barrel (in Volt) - float mOBVbb = 0.0; ///< back bias absolute value for ITS Outter Barrel (in Volt) + float mOBVbb = 0.0; ///< back bias absolute value for ITS Outer Barrel (in Volt) + + std::vector mROFrameLayerLengthInBC; ///< staggering ROF length in BC for continuous mode per layer + std::vector mROFrameLayerBiasInBC; ///< staggering ROF bias in BC for continuous mode per layer + std::vector mROFrameLayerLength; ///< staggering ROF length in ns for continuous mode per layer + std::vector mStrobeLayerLength; ///< staggering length of the strobe in ns (sig. over threshold checked in this window only) + std::vector mStrobeLayerDelay; ///< staggering delay of the strobe in ns o2::itsmft::AlpideSignalTrapezoid mSignalShape; ///< signal timeshape parameterization const o2::itsmft::AlpideSimResponse* mAlpSimResponse = nullptr; //!< pointer on external response // auxiliary precalculated parameters - float mROFrameLengthInv = 0; ///< inverse length of RO frame in ns - float mNSimStepsInv = 0; ///< its inverse + float mROFrameLengthInv = 0; ///< inverse length of RO frame in ns + std::vector mROFrameLayerLengthInv; // inverse length of RO frame in ns per layer + float mNSimStepsInv = 0; ///< its inverse - ClassDef(DigiParams, 2); + ClassDef(DigiParams, 3); }; } // namespace itsmft } // namespace o2 diff --git a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Digitizer.h b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Digitizer.h index 670dd32bf9f46..c81e2d9476644 100644 --- a/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Digitizer.h +++ b/Detectors/ITSMFT/common/simulation/include/ITSMFTSimulation/Digitizer.h @@ -49,6 +49,8 @@ class Digitizer : public TObject public: Digitizer() = default; + Digitizer(Digitizer&&) = delete; + Digitizer& operator=(Digitizer&&) = delete; ~Digitizer() override = default; Digitizer(const Digitizer&) = delete; Digitizer& operator=(const Digitizer&) = delete; @@ -56,7 +58,7 @@ class Digitizer : public TObject void setDigits(std::vector* dig) { mDigits = dig; } void setMCLabels(o2::dataformats::MCTruthContainer* mclb) { mMCLabels = mclb; } void setROFRecords(std::vector* rec) { mROFRecords = rec; } - o2::itsmft::DigiParams& getParams() { return (o2::itsmft::DigiParams&)mParams; } + o2::itsmft::DigiParams& getParams() { return mParams; } const o2::itsmft::DigiParams& getParams() const { return mParams; } void setNoiseMap(const o2::itsmft::NoiseMap* mp) { mNoiseMap = mp; } void setDeadChannelsMap(const o2::itsmft::NoiseMap* mp) { mDeadChanMap = mp; } @@ -67,17 +69,17 @@ class Digitizer : public TObject auto getChipResponse(int chipID); /// Steer conversion of hits to digits - void process(const std::vector* hits, int evID, int srcID); - void setEventTime(const o2::InteractionTimeRecord& irt); + void process(const std::vector* hits, int evID, int srcID, int layer = -1); + void setEventTime(const o2::InteractionTimeRecord& irt, int layer = -1); double getEndTimeOfROFMax() const { ///< return the time corresponding to end of the last reserved ROFrame : mROFrameMax - return mParams.getROFrameLength() * (mROFrameMax + 1) + mParams.getTimeOffset(); + return (mParams.getROFrameLength() * (double)(mROFrameMax + 1)) + mParams.getTimeOffset(); } void setContinuous(bool v) { mParams.setContinuous(v); } bool isContinuous() const { return mParams.isContinuous(); } - void fillOutputContainer(uint32_t maxFrame = 0xffffffff); + void fillOutputContainer(uint32_t maxFrame = 0xffffffff, int layer = -1); void setDigiParams(const o2::itsmft::DigiParams& par) { mParams = par; } const o2::itsmft::DigiParams& getDigitParams() const { return mParams; } @@ -92,11 +94,17 @@ class Digitizer : public TObject mEventROFrameMin = 0xffffffff; mEventROFrameMax = 0; } + void resetROFrameBounds() + { + mROFrameMin = 0; + mROFrameMax = 0; + mNewROFrame = 0; + } private: - void processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID, int srcID); + void processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID, int srcID, int lay); void registerDigits(ChipDigitsContainer& chip, uint32_t roFrame, float tInROF, int nROF, - uint16_t row, uint16_t col, int nEle, o2::MCCompLabel& lbl); + uint16_t row, uint16_t col, int nEle, o2::MCCompLabel& lbl, int lay); ExtraDig* getExtraDigBuffer(uint32_t roFrame) { @@ -115,7 +123,7 @@ class Digitizer : public TObject o2::itsmft::DigiParams mParams; ///< digitization parameters o2::InteractionTimeRecord mEventTime; ///< global event time and interaction record o2::InteractionRecord mIRFirstSampledTF; ///< IR of the 1st sampled IR, noise-only ROFs will be inserted till this IR only - double mCollisionTimeWrtROF; + double mCollisionTimeWrtROF{}; uint32_t mROFrameMin = 0; ///< lowest RO frame of current digits uint32_t mROFrameMax = 0; ///< highest RO frame of current digits uint32_t mNewROFrame = 0; ///< ROFrame corresponding to provided time diff --git a/Detectors/ITSMFT/common/simulation/src/DigiParams.cxx b/Detectors/ITSMFT/common/simulation/src/DigiParams.cxx index ffba627265cc7..a7c5c32b6351d 100644 --- a/Detectors/ITSMFT/common/simulation/src/DigiParams.cxx +++ b/Detectors/ITSMFT/common/simulation/src/DigiParams.cxx @@ -26,12 +26,17 @@ DigiParams::DigiParams() setNSimSteps(mNSimSteps); } -void DigiParams::setROFrameLength(float lNS) +void DigiParams::setROFrameLength(float lNS, int layer) { // set ROFrame length in nanosecongs - mROFrameLength = lNS; - assert(mROFrameLength > 1.); - mROFrameLengthInv = 1. / mROFrameLength; + assert(lNS > 1.f); + if (layer < 0) { + mROFrameLength = lNS; + mROFrameLengthInv = 1.f / mROFrameLength; + } else { + mROFrameLayerLength.push_back(lNS); + mROFrameLayerLengthInv.push_back(1.f / lNS); + } } void DigiParams::setNSimSteps(int v) @@ -58,17 +63,24 @@ void DigiParams::setChargeThreshold(int v, float frac2Account) //______________________________________________ void DigiParams::print() const { - // print settings - printf("Alpide digitization params:\n"); - printf("Continuous readout : %s\n", mIsContinuous ? "ON" : "OFF"); - printf("Readout Frame Length(ns) : %f\n", mROFrameLength); - printf("Strobe delay (ns) : %f\n", mStrobeDelay); - printf("Strobe length (ns) : %f\n", mStrobeLength); - printf("Threshold (N electrons) : %d\n", mChargeThreshold); - printf("Min N electrons to account : %d\n", mMinChargeToAccount); - printf("Number of charge sharing steps : %d\n", mNSimSteps); - printf("ELoss to N electrons factor : %e\n", mEnergyToNElectrons); - printf("Noise level per pixel : %e\n", mNoisePerPixel); - printf("Charge time-response:\n"); + LOGF(info, "Alpide digitization params:"); + LOGF(info, "Continuous readout : %s", mIsContinuous ? "ON" : "OFF"); + if (withStaggering()) { + for (int i{0}; i < (int)mROFrameLayerLengthInBC.size(); ++i) { + LOGF(info, " Readout Frame Layer:%d Length(ns)[BC] : %f [%d]", i, mROFrameLayerLength[i], mROFrameLayerLengthInBC[i]); + LOGF(info, "Strobe delay Layer %d (ns) : %f", i, mStrobeDelay); + LOGF(info, "Strobe length Layer %d (ns) : %f", i, mStrobeLength); + } + } else { + LOGF(info, "Readout Frame Length(ns) : %f", mROFrameLength); + LOGF(info, "Strobe delay (ns) : %f", mStrobeDelay); + LOGF(info, "Strobe length (ns) : %f", mStrobeLength); + } + LOGF(info, "Threshold (N electrons) : %d", mChargeThreshold); + LOGF(info, "Min N electrons to account : %d", mMinChargeToAccount); + LOGF(info, "Number of charge sharing steps : %d", mNSimSteps); + LOGF(info, "ELoss to N electrons factor : %e", mEnergyToNElectrons); + LOGF(info, "Noise level per pixel : %e", mNoisePerPixel); + LOGF(info, "Charge time-response:"); mSignalShape.print(); } diff --git a/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx b/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx index 4a8af0cbe9737..b1a92e988968b 100644 --- a/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx +++ b/Detectors/ITSMFT/common/simulation/src/Digitizer.cxx @@ -13,6 +13,7 @@ /// \brief Implementation of the ITS/MFT digitizer #include "DataFormatsITSMFT/Digit.h" +#include "Framework/Logger.h" #include "ITSMFTBase/SegmentationAlpide.h" #include "ITSMFTSimulation/DPLDigitizerParam.h" #include "ITSMFTSimulation/Digitizer.h" @@ -21,10 +22,11 @@ #include "DetectorsRaw/HBFUtils.h" #include +#include #include #include +#include #include -#include // for LOG using o2::itsmft::Digit; using o2::itsmft::Hit; @@ -73,14 +75,14 @@ void Digitizer::init() } else { LOG(fatal) << "Invalid ITS Inner Barrel back-bias value"; } - if (doptITS.OBVbb == 0.0) { // for ITS Outter Barrel + if (doptITS.OBVbb == 0.0) { // for ITS Outer Barrel mAlpSimRespOB = mAlpSimResp[0]; LOG(info) << "Choosing Vbb=0V for ITS OB"; } else if (doptITS.OBVbb == 3.0) { mAlpSimRespOB = mAlpSimResp[1]; LOG(info) << "Choosing Vbb=-3V for ITS OB"; } else { - LOG(fatal) << "Invalid ITS Outter Barrel back-bias value"; + LOG(fatal) << "Invalid ITS Outer Barrel back-bias value"; } mParams.print(); mIRFirstSampledTF = o2::raw::HBFUtils::Instance().getFirstSampledTFIR(); @@ -98,47 +100,53 @@ auto Digitizer::getChipResponse(int chipID) if (chipID < 432) { // in ITS Inner Barrel return mAlpSimRespIB; - } else { // in ITS Outter Barrel + } else { // in ITS Outer Barrel return mAlpSimRespOB; } } //_______________________________________________________________________ -void Digitizer::process(const std::vector* hits, int evID, int srcID) +void Digitizer::process(const std::vector* hits, int evID, int srcID, int layer) { // digitize single event, the time must have been set beforehand + // opt. apply a filter on the layer of the processed hits - LOG(debug) << "Digitizing " << mGeometry->getName() << " hits of entry " << evID << " from source " + LOG(debug) << "Digitizing " << mGeometry->getName() << ":" << layer << " hits of entry " << evID << " from source " << srcID << " at time " << mEventTime << " ROFrame= " << mNewROFrame << ")" << " cont.mode: " << isContinuous() << " Min/Max ROFrames " << mROFrameMin << "/" << mROFrameMax; // is there something to flush ? if (mNewROFrame > mROFrameMin) { - fillOutputContainer(mNewROFrame - 1); // flush out all frame preceding the new one + fillOutputContainer(mNewROFrame - 1, layer); // flush out all frame preceding the new one } int nHits = hits->size(); std::vector hitIdx(nHits); std::iota(std::begin(hitIdx), std::end(hitIdx), 0); // sort hits to improve memory access - std::sort(hitIdx.begin(), hitIdx.end(), - [hits](auto lhs, auto rhs) { - return (*hits)[lhs].GetDetectorID() < (*hits)[rhs].GetDetectorID(); - }); - for (int i : hitIdx) { - processHit((*hits)[i], mROFrameMax, evID, srcID); + std::sort(hitIdx.begin(), hitIdx.end(), [hits](auto lhs, auto rhs) { + return (*hits)[lhs].GetDetectorID() < (*hits)[rhs].GetDetectorID(); + }); + for (int i : hitIdx | std::views::filter([&](int idx) { + if (layer < 0) { + return true; + } + return mGeometry->getLayer((*hits)[idx].GetDetectorID()) == layer; + })) { + processHit((*hits)[i], mROFrameMax, evID, srcID, layer); } + // in the triggered mode store digits after every MC event // TODO: in the real triggered mode this will not be needed, this is actually for the // single event processing only if (!mParams.isContinuous()) { - fillOutputContainer(mROFrameMax); + fillOutputContainer(mROFrameMax, layer); } } //_______________________________________________________________________ -void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt) +void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt, int layer) { // assign event time in ns mEventTime = irt; @@ -161,13 +169,13 @@ void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt) // this event is before the first RO mIsBeforeFirstRO = true; } else { - mNewROFrame = nbc / mParams.getROFrameLengthInBC(); + mNewROFrame = nbc / mParams.getROFrameLengthInBC(layer); mIsBeforeFirstRO = false; } LOG(debug) << " NewROFrame " << mNewROFrame << " nbc " << nbc; // in continuous mode depends on starts of periodic readout frame - mCollisionTimeWrtROF += (nbc % mParams.getROFrameLengthInBC()) * o2::constants::lhc::LHCBunchSpacingNS; + mCollisionTimeWrtROF += (nbc % mParams.getROFrameLengthInBC(layer)) * o2::constants::lhc::LHCBunchSpacingNS; } else { mNewROFrame = 0; } @@ -183,16 +191,14 @@ void Digitizer::setEventTime(const o2::InteractionTimeRecord& irt) } //_______________________________________________________________________ -void Digitizer::fillOutputContainer(uint32_t frameLast) +void Digitizer::fillOutputContainer(uint32_t frameLast, int layer) { // fill output with digits from min.cached up to requested frame, generating the noise beforehand - if (frameLast > mROFrameMax) { - frameLast = mROFrameMax; - } + frameLast = std::min(frameLast, mROFrameMax); // make sure all buffers for extra digits are created up to the maxFrame getExtraDigBuffer(mROFrameMax); - LOG(info) << "Filling " << mGeometry->getName() << " digits output for RO frames " << mROFrameMin << ":" + LOG(info) << "Filling " << mGeometry->getName() << " digits:" << layer << " output for RO frames " << mROFrameMin << ":" << frameLast; o2::itsmft::ROFRecord rcROF; @@ -204,7 +210,7 @@ void Digitizer::fillOutputContainer(uint32_t frameLast) auto& extra = *(mExtraBuff.front().get()); for (auto& chip : mChips) { - if (chip.isDisabled()) { + if (chip.isDisabled() || (layer >= 0 && mGeometry->getLayer(chip.getChipIndex()) != layer)) { continue; } chip.addNoise(mROFrameMin, mROFrameMin, &mParams); @@ -236,7 +242,7 @@ void Digitizer::fillOutputContainer(uint32_t frameLast) // finalize ROF record rcROF.setNEntries(mDigits->size() - rcROF.getFirstEntry()); // number of digits if (isContinuous()) { - rcROF.getBCData().setFromLong(mIRFirstSampledTF.toLong() + mROFrameMin * mParams.getROFrameLengthInBC()); + rcROF.getBCData().setFromLong(mIRFirstSampledTF.toLong() + mROFrameMin * mParams.getROFrameLengthInBC(layer)); } else { rcROF.getBCData() = mEventTime; // RSTODO do we need to add trigger delay? } @@ -251,7 +257,7 @@ void Digitizer::fillOutputContainer(uint32_t frameLast) } //_______________________________________________________________________ -void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID, int srcID) +void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID, int srcID, int lay) { // convert single hit to digits auto chipID = hit.GetDetectorID(); @@ -284,14 +290,12 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID } float tTot = mParams.getSignalShape().getMaxDuration(); // frame of the hit signal start wrt event ROFrame - int roFrameRel = int(timeInROF * mParams.getROFrameLengthInv()); + int roFrameRel = int(timeInROF * mParams.getROFrameLengthInv(lay)); // frame of the hit signal end wrt event ROFrame: in the triggered mode we read just 1 frame - uint32_t roFrameRelMax = mParams.isContinuous() ? (timeInROF + tTot) * mParams.getROFrameLengthInv() : roFrameRel; + uint32_t roFrameRelMax = mParams.isContinuous() ? (timeInROF + tTot) * mParams.getROFrameLengthInv(lay) : roFrameRel; int nFrames = roFrameRelMax + 1 - roFrameRel; uint32_t roFrameMax = mNewROFrame + roFrameRelMax; - if (roFrameMax > maxFr) { - maxFr = roFrameMax; // if signal extends beyond current maxFrame, increase the latter - } + maxFr = std::max(roFrameMax, maxFr); // if signal extends beyond current maxFrame, increase the latter // here we start stepping in the depth of the sensor to generate charge diffusion float nStepsInv = mParams.getNSimStepsInv(); @@ -332,17 +336,13 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID } rowS -= AlpideRespSimMat::NPix / 2; rowE += AlpideRespSimMat::NPix / 2; - if (rowS < 0) { - rowS = 0; - } + rowS = std::max(rowS, 0); if (rowE >= Segmentation::NRows) { rowE = Segmentation::NRows - 1; } colS -= AlpideRespSimMat::NPix / 2; colE += AlpideRespSimMat::NPix / 2; - if (colS < 0) { - colS = 0; - } + colS = std::max(colS, 0); if (colE >= Segmentation::NCols) { colE = Segmentation::NCols - 1; } @@ -362,7 +362,7 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID const o2::itsmft::AlpideSimResponse* resp = getChipResponse(chipID); - // take into account that the AlpideSimResponse depth defintion has different min/max boundaries + // take into account that the AlpideSimResponse depth definition has different min/max boundaries // although the max should coincide with the surface of the epitaxial layer, which in the chip // local coordinates has Y = +SensorLayerThickness/2 @@ -379,7 +379,7 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID rowPrev = row; colPrev = col; } - bool flipCol, flipRow; + bool flipCol = false, flipRow = false; // note that response needs coordinates along column row (locX) (locZ) then depth (locY) auto rspmat = resp->getResponse(xyzLocS.X() - cRowPix, xyzLocS.Z() - cColPix, xyzLocS.Y(), flipRow, flipCol); @@ -389,12 +389,12 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID } for (int irow = AlpideRespSimMat::NPix; irow--;) { - int rowDest = row + irow - AlpideRespSimMat::NPix / 2 - rowS; // destination row in the respMatrix + int rowDest = row + irow - (AlpideRespSimMat::NPix / 2) - rowS; // destination row in the respMatrix if (rowDest < 0 || rowDest >= rowSpan) { continue; } for (int icol = AlpideRespSimMat::NPix; icol--;) { - int colDest = col + icol - AlpideRespSimMat::NPix / 2 - colS; // destination column in the respMatrix + int colDest = col + icol - (AlpideRespSimMat::NPix / 2) - colS; // destination column in the respMatrix if (colDest < 0 || colDest >= colSpan) { continue; } @@ -426,35 +426,31 @@ void Digitizer::processHit(const o2::itsmft::Hit& hit, uint32_t& maxFr, int evID continue; } // - registerDigits(chip, roFrameAbs, timeInROF, nFrames, rowIS, colIS, nEle, lbl); + registerDigits(chip, roFrameAbs, timeInROF, nFrames, rowIS, colIS, nEle, lbl, lay); } } } //________________________________________________________________________________ void Digitizer::registerDigits(ChipDigitsContainer& chip, uint32_t roFrame, float tInROF, int nROF, - uint16_t row, uint16_t col, int nEle, o2::MCCompLabel& lbl) + uint16_t row, uint16_t col, int nEle, o2::MCCompLabel& lbl, int lay) { // Register digits for given pixel, accounting for the possible signal contribution to // multiple ROFrame. The signal starts at time tInROF wrt the start of provided roFrame // In every ROFrame we check the collected signal during strobe - float tStrobe = mParams.getStrobeDelay() - tInROF; // strobe start wrt signal start + float tStrobe = mParams.getStrobeDelay(lay) - tInROF; // strobe start wrt signal start for (int i = 0; i < nROF; i++) { uint32_t roFr = roFrame + i; - int nEleROF = mParams.getSignalShape().getCollectedCharge(nEle, tStrobe, tStrobe + mParams.getStrobeLength()); - tStrobe += mParams.getROFrameLength(); // for the next ROF + int nEleROF = mParams.getSignalShape().getCollectedCharge(nEle, tStrobe, tStrobe + mParams.getStrobeLength(lay)); + tStrobe += mParams.getROFrameLength(lay); // for the next ROF // discard too small contributions, they have no chance to produce a digit if (nEleROF < mParams.getMinChargeToAccount()) { continue; } - if (roFr > mEventROFrameMax) { - mEventROFrameMax = roFr; - } - if (roFr < mEventROFrameMin) { - mEventROFrameMin = roFr; - } + mEventROFrameMax = std::max(roFr, mEventROFrameMax); + mEventROFrameMin = std::min(roFr, mEventROFrameMin); auto key = chip.getOrderingKey(roFr, row, col); PreDigit* pd = chip.findDigit(key); if (!pd) { diff --git a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DigitReaderSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DigitReaderSpec.h index e655e05842d71..348ba76468144 100644 --- a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DigitReaderSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DigitReaderSpec.h @@ -16,6 +16,7 @@ #include "TFile.h" #include "TTree.h" +#include "ITSMFTBase/DPLAlpideParam.h" #include "DataFormatsITSMFT/Digit.h" #include "DataFormatsITSMFT/GBTCalibData.h" #include "DataFormatsITSMFT/ROFRecord.h" @@ -34,64 +35,67 @@ namespace o2 namespace itsmft { +template class DigitReader : public Task { public: + static constexpr o2::detectors::DetID ID{N == o2::detectors::DetID::ITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT}; + static constexpr o2::header::DataOrigin Origin{N == o2::detectors::DetID::ITS ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; + static constexpr int NLayers{o2::itsmft::DPLAlpideParam::getNLayers()}; + static constexpr int RLayers = o2::itsmft::DPLAlpideParam::supportsStaggering() ? NLayers : 1; + DigitReader() = delete; - DigitReader(o2::detectors::DetID id, bool useMC, bool useCalib, bool triggerOut); + DigitReader(bool useMC, bool useCalib, bool triggerOut); ~DigitReader() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; protected: void connectTree(const std::string& filename); + template + void setBranchAddress(const std::string& base, Ptr& addr, int layer = -1); + std::string getBranchName(const std::string& base, int index); - std::vector mDigits, *mDigitsPtr = &mDigits; + std::array*, NLayers> mDigits; std::vector mCalib, *mCalibPtr = &mCalib; - std::vector mDigROFRec, *mDigROFRecPtr = &mDigROFRec; - std::vector mDigMC2ROFs, *mDigMC2ROFsPtr = &mDigMC2ROFs; - o2::dataformats::ConstMCTruthContainer mConstLabels; - o2::header::DataOrigin mOrigin = o2::header::gDataOriginInvalid; + std::array*, NLayers> mDigROFRec; + std::array*, NLayers> mDigMC2ROFs; + std::array, NLayers> mConstLabels; + std::array mPLabels; std::unique_ptr mFile; std::unique_ptr mTree; - bool mUseMC = true; // use MC truth - bool mUseCalib = true; // send calib data - bool mTriggerOut = true; // send dummy triggers vector + bool mUseMC = true; // use MC truth + bool mUseCalib = true; // send calib data + bool mTriggerOut = true; // send dummy triggers vector bool mUseIRFrames = false; // selected IRFrames modes int mROFBiasInBC = 0; int mROFLengthInBC = 0; int mNRUs = 0; - std::string mDetName = ""; - std::string mDetNameLC = ""; - std::string mFileName = ""; + std::string mDetName; + std::string mDetNameLC; + std::string mFileName; std::string mDigTreeName = "o2sim"; std::string mDigitBranchName = "Digit"; - std::string mDigROFBranchName = "DigitROF"; + std::string mDigitROFBranchName = "DigitROF"; std::string mCalibBranchName = "Calib"; - std::string mDigtMCTruthBranchName = "DigitMCTruth"; - std::string mDigtMC2ROFBranchName = "DigitMC2ROF"; + std::string mDigitMCTruthBranchName = "DigitMCTruth"; + std::string mDigitMC2ROFBranchName = "DigitMC2ROF"; }; -class ITSDigitReader : public DigitReader +class ITSDigitReader : public DigitReader { public: ITSDigitReader(bool useMC = true, bool useCalib = false, bool useTriggers = true) - : DigitReader(o2::detectors::DetID::ITS, useMC, useCalib, useTriggers) - { - mOrigin = o2::header::gDataOriginITS; - } + : DigitReader(useMC, useCalib, useTriggers) {} }; -class MFTDigitReader : public DigitReader +class MFTDigitReader : public DigitReader { public: MFTDigitReader(bool useMC = true, bool useCalib = false, bool useTriggers = true) - : DigitReader(o2::detectors::DetID::MFT, useMC, useCalib, useTriggers) - { - mOrigin = o2::header::gDataOriginMFT; - } + : DigitReader(useMC, useCalib, useTriggers) {} }; /// create a processor spec diff --git a/Detectors/ITSMFT/common/workflow/src/DigitReaderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/DigitReaderSpec.cxx index 3c7a86fe173d6..ec86da4833a0d 100644 --- a/Detectors/ITSMFT/common/workflow/src/DigitReaderSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/DigitReaderSpec.cxx @@ -11,6 +11,7 @@ /// @file DigitReaderSpec.cxx +#include #include #include "TTree.h" @@ -39,25 +40,28 @@ namespace o2 namespace itsmft { -DigitReader::DigitReader(o2::detectors::DetID id, bool useMC, bool useCalib, bool triggerOut) +template +DigitReader::DigitReader(bool useMC, bool useCalib, bool triggerOut) : mUseMC(useMC), mUseCalib(useCalib), mTriggerOut(triggerOut), mDetNameLC(mDetName = ID.getName()), mDigTreeName("o2sim") { - assert(id == o2::detectors::DetID::ITS || id == o2::detectors::DetID::MFT); - mDetNameLC = mDetName = id.getName(); - mDigTreeName = "o2sim"; - mDigitBranchName = mDetName + mDigitBranchName; - mDigROFBranchName = mDetName + mDigROFBranchName; + mDigitROFBranchName = mDetName + mDigitROFBranchName; mCalibBranchName = mDetName + mCalibBranchName; - mDigtMCTruthBranchName = mDetName + mDigtMCTruthBranchName; - mDigtMC2ROFBranchName = mDetName + mDigtMC2ROFBranchName; - mTriggerOut = triggerOut; - mUseMC = useMC; - mUseCalib = useCalib; + mDigitMCTruthBranchName = mDetName + mDigitMCTruthBranchName; + mDigitMC2ROFBranchName = mDetName + mDigitMC2ROFBranchName; + std::transform(mDetNameLC.begin(), mDetNameLC.end(), mDetNameLC.begin(), ::tolower); + + for (uint32_t i = 0; i < NLayers; ++i) { + mDigits[i] = nullptr; + mDigROFRec[i] = nullptr; + mDigMC2ROFs[i] = nullptr; + mPLabels[i] = nullptr; + } } -void DigitReader::init(InitContext& ic) +template +void DigitReader::init(InitContext& ic) { mFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get("input-dir")), ic.options().get((mDetNameLC + "-digit-infile").c_str())); @@ -67,23 +71,23 @@ void DigitReader::init(InitContext& ic) connectTree(mFileName); } -void DigitReader::run(ProcessingContext& pc) +template +void DigitReader::run(ProcessingContext& pc) { const auto& tinfo = pc.services().get(); + const auto& alpideParam = o2::itsmft::DPLAlpideParam::Instance(); if (tinfo.globalRunNumberChanged && mUseIRFrames) { // new run is starting: 1st call // TODO: we have to find a way define CCDBInput for IRFrames mode only using DPL fetcher auto& ccdb = o2::ccdb::BasicCCDBManager::instance(); auto rlim = ccdb.getRunDuration(tinfo.runNumber); long ts = (rlim.first + rlim.second) / 2; - if (mOrigin == o2::header::gDataOriginITS) { + if constexpr (N == o2::detectors::DetID::ITS) { ccdb.getForTimeStamp>("ITS/Config/AlpideParam", ts); - const auto& alpideParam = o2::itsmft::DPLAlpideParam::Instance(); mROFBiasInBC = alpideParam.roFrameBiasInBC; mROFLengthInBC = alpideParam.roFrameLengthInBC; mNRUs = o2::itsmft::ChipMappingITS::getNRUs(); } else { ccdb.getForTimeStamp>("MFT/Config/AlpideParam", ts); - const auto& alpideParam = o2::itsmft::DPLAlpideParam::Instance(); mROFBiasInBC = alpideParam.roFrameBiasInBC; mROFLengthInBC = alpideParam.roFrameLengthInBC; mNRUs = o2::itsmft::ChipMappingMFT::getNRUs(); @@ -93,38 +97,37 @@ void DigitReader::run(ProcessingContext& pc) if (mUseIRFrames) { irFrames = pc.inputs().get>("driverInfo"); } - static o2::dataformats::IOMCTruthContainerView* plabels = nullptr; - if (mUseMC && !plabels) { - mTree->SetBranchAddress(mDigtMCTruthBranchName.c_str(), &plabels); - } - auto ent = mTree->GetReadEntry(); + auto ent = mTree->GetReadEntry(); if (!mUseIRFrames) { ent++; assert(ent < mTree->GetEntries()); // this should not happen mTree->GetEntry(ent); - LOG(info) << mDetName << "DigitReader pushes " << mDigROFRec.size() << " ROFRecords, " << mDigits.size() << " digits at entry " << ent; - pc.outputs().snapshot(Output{mOrigin, "DIGITSROF", 0}, mDigROFRec); - pc.outputs().snapshot(Output{mOrigin, "DIGITS", 0}, mDigits); + for (uint32_t iLayer = 0; iLayer < RLayers; ++iLayer) { + LOG(info) << mDetName << "DigitReader:" << iLayer << " pushes " << mDigROFRec[iLayer]->size() << " ROFRecords, " << mDigits[iLayer]->size() << " digits at entry " << ent; + pc.outputs().snapshot(Output{Origin, "DIGITSROF", iLayer}, *mDigROFRec[iLayer]); + pc.outputs().snapshot(Output{Origin, "DIGITS", iLayer}, *mDigits[iLayer]); + if (mUseMC) { + auto& sharedlabels = pc.outputs().make>(Output{Origin, "DIGITSMCTR", iLayer}); + mPLabels[iLayer]->copyandflatten(sharedlabels); + delete mPLabels[iLayer]; + mPLabels[iLayer] = nullptr; + pc.outputs().snapshot(Output{Origin, "DIGITSMC2ROF", iLayer}, *mDigMC2ROFs[iLayer]); + } + } if (mUseCalib) { - pc.outputs().snapshot(Output{mOrigin, "GBTCALIB", 0}, mCalib); + pc.outputs().snapshot(Output{Origin, "GBTCALIB", 0}, mCalib); } if (mTriggerOut) { std::vector dummyTrig; - pc.outputs().snapshot(Output{mOrigin, "PHYSTRIG", 0}, dummyTrig); - } - if (mUseMC) { - auto& sharedlabels = pc.outputs().make>(Output{mOrigin, "DIGITSMCTR", 0}); - plabels->copyandflatten(sharedlabels); - delete plabels; - plabels = nullptr; - pc.outputs().snapshot(Output{mOrigin, "DIGITSMC2ROF", 0}, mDigMC2ROFs); + pc.outputs().snapshot(Output{Origin, "PHYSTRIG", 0}, dummyTrig); } if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { pc.services().get().endOfStream(); pc.services().get().readyToQuit(QuitRequest::Me); } } else { // need to select particulars IRs range, presumably from the same tree entry + // TODO implement for staggering std::vector digitsSel; std::vector calibSel; std::vector digROFRecSel; @@ -144,33 +147,33 @@ void DigitReader::run(ProcessingContext& pc) // do we need to read a new entry? if (ent > mTree->GetReadEntry()) { if (mUseMC) { - delete plabels; - plabels = nullptr; - mConstLabels.clear(); - mTree->SetBranchAddress(mDigtMCTruthBranchName.c_str(), &plabels); + delete mPLabels[0]; + mPLabels[0] = nullptr; + mConstLabels[0].clear(); + mTree->SetBranchAddress(mDigitMCTruthBranchName.c_str(), &mPLabels[0]); } mTree->GetEntry(ent); if (mUseMC) { - plabels->copyandflatten(mConstLabels); - delete plabels; - plabels = nullptr; + mPLabels[0]->copyandflatten(mConstLabels[0]); + delete mPLabels[0]; + mPLabels[0] = nullptr; } } std::vector rofOld2New; - rofOld2New.resize(mDigROFRec.size(), -1); + rofOld2New.resize(mDigROFRec[0]->size(), -1); - if (mDigROFRec.front().getBCData() <= irMax && (mDigROFRec.back().getBCData() + mROFLengthInBC - 1) >= irMin) { // there is an overlap - for (int irof = 0; irof < (int)mDigROFRec.size(); irof++) { - const auto& rof = mDigROFRec[irof]; + if (mDigROFRec[0]->front().getBCData() <= irMax && (mDigROFRec[0]->back().getBCData() + mROFLengthInBC - 1) >= irMin) { // there is an overlap + for (int irof = 0; irof < (int)mDigROFRec[0]->size(); irof++) { + const auto& rof = mDigROFRec[0]->at(irof); if (irfSel.check({rof.getBCData(), rof.getBCData() + mROFLengthInBC - 1}) != -1) { rofOld2New[irof] = (int)digROFRecSel.size(); LOGP(debug, "Adding selected ROF {}", rof.getBCData().asString()); digROFRecSel.push_back(rof); int offs = digitsSel.size(); digROFRecSel.back().setFirstEntry(offs); - std::copy(mDigits.begin() + rof.getFirstEntry(), mDigits.begin() + rof.getFirstEntry() + rof.getNEntries(), std::back_inserter(digitsSel)); + std::copy(mDigits[0]->begin() + rof.getFirstEntry(), mDigits[0]->begin() + rof.getFirstEntry() + rof.getNEntries(), std::back_inserter(digitsSel)); for (int id = 0; id < rof.getNEntries(); id++) { // copy MC info - digitLabelsSel.addElements(id + offs, mConstLabels.getLabels(id + rof.getFirstEntry())); + digitLabelsSel.addElements(id + offs, mConstLabels[0].getLabels(id + rof.getFirstEntry())); } if (mCalib.size() >= size_t((irof + 1) * mNRUs)) { std::copy(mCalib.begin() + irof * mNRUs, mCalib.begin() + (irof + 1) * mNRUs, std::back_inserter(calibSel)); @@ -179,7 +182,7 @@ void DigitReader::run(ProcessingContext& pc) } } if (mUseMC) { - digMC2ROFsSel = mDigMC2ROFs; + digMC2ROFsSel = *mDigMC2ROFs[0]; for (auto& mc2rof : digMC2ROFsSel) { if (mc2rof.rofRecordID < 0) { continue; // did not contribute even to the original data @@ -198,26 +201,26 @@ void DigitReader::run(ProcessingContext& pc) mc2rof.maxROF = mx; } } - if (mDigROFRec.back().getBCData() + mROFLengthInBC - 1 < irMax) { // need to check the next entry + if (mDigROFRec[0]->back().getBCData() + mROFLengthInBC - 1 < irMax) { // need to check the next entry ent++; continue; } break; // push collected data } } - pc.outputs().snapshot(Output{mOrigin, "DIGITSROF", 0}, digROFRecSel); - pc.outputs().snapshot(Output{mOrigin, "DIGITS", 0}, digitsSel); + pc.outputs().snapshot(Output{Origin, "DIGITSROF", 0}, digROFRecSel); + pc.outputs().snapshot(Output{Origin, "DIGITS", 0}, digitsSel); if (mUseCalib) { - pc.outputs().snapshot(Output{mOrigin, "GBTCALIB", 0}, calibSel); + pc.outputs().snapshot(Output{Origin, "GBTCALIB", 0}, calibSel); } if (mTriggerOut) { std::vector dummyTrig; - pc.outputs().snapshot(Output{mOrigin, "PHYSTRIG", 0}, dummyTrig); + pc.outputs().snapshot(Output{Origin, "PHYSTRIG", 0}, dummyTrig); } if (mUseMC) { - auto& sharedlabels = pc.outputs().make>(Output{mOrigin, "DIGITSMCTR", 0}); + auto& sharedlabels = pc.outputs().make>(Output{Origin, "DIGITSMCTR", 0}); digitLabelsSel.flatten_to(sharedlabels); - pc.outputs().snapshot(Output{mOrigin, "DIGITSMC2ROF", 0}, digMC2ROFsSel); + pc.outputs().snapshot(Output{Origin, "DIGITSMC2ROF", 0}, digMC2ROFsSel); } if (!irFrames.size() || irFrames.back().isLast()) { @@ -227,77 +230,99 @@ void DigitReader::run(ProcessingContext& pc) } } -void DigitReader::connectTree(const std::string& filename) +template +void DigitReader::connectTree(const std::string& filename) { mTree.reset(nullptr); // in case it was already loaded mFile.reset(TFile::Open(filename.c_str())); assert(mFile && !mFile->IsZombie()); mTree.reset((TTree*)mFile->Get(mDigTreeName.c_str())); assert(mTree); - - mTree->SetBranchAddress(mDigROFBranchName.c_str(), &mDigROFRecPtr); - mTree->SetBranchAddress(mDigitBranchName.c_str(), &mDigitsPtr); + for (uint32_t iLayer = 0; iLayer < RLayers; ++iLayer) { + setBranchAddress(mDigitROFBranchName, mDigROFRec[iLayer], iLayer); + setBranchAddress(mDigitBranchName, mDigits[iLayer], iLayer); + if (mUseMC) { + if (!mTree->GetBranch(getBranchName(mDigitMC2ROFBranchName, iLayer).c_str()) || !mTree->GetBranch(getBranchName(mDigitMCTruthBranchName, iLayer).c_str())) { + throw std::runtime_error("MC data requested but not found in the tree"); + } + setBranchAddress(mDigitMC2ROFBranchName, mDigMC2ROFs[iLayer], iLayer); + if (!mPLabels[iLayer]) { + setBranchAddress(mDigitMCTruthBranchName, mPLabels[iLayer], iLayer); + } + } + } if (mUseCalib) { if (!mTree->GetBranch(mCalibBranchName.c_str())) { throw std::runtime_error("GBT calibration data requested but not found in the tree"); } - mTree->SetBranchAddress(mCalibBranchName.c_str(), &mCalibPtr); - } - if (mUseMC) { - if (!mTree->GetBranch(mDigtMC2ROFBranchName.c_str()) || !mTree->GetBranch(mDigtMCTruthBranchName.c_str())) { - throw std::runtime_error("MC data requested but not found in the tree"); - } - mTree->SetBranchAddress(mDigtMC2ROFBranchName.c_str(), &mDigMC2ROFsPtr); + setBranchAddress(mCalibBranchName, mCalibPtr); } LOG(info) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; } -DataProcessorSpec getITSDigitReaderSpec(bool useMC, bool useCalib, bool useTriggers, std::string defname) +template +std::string DigitReader::getBranchName(const std::string& base, int index) { - std::vector outputSpec; - outputSpec.emplace_back("ITS", "DIGITS", 0, Lifetime::Timeframe); - outputSpec.emplace_back("ITS", "DIGITSROF", 0, Lifetime::Timeframe); - if (useCalib) { - outputSpec.emplace_back("ITS", "GBTCALIB", 0, Lifetime::Timeframe); + if constexpr (!o2::itsmft::DPLAlpideParam::supportsStaggering()) { + return base; } - if (useMC) { - outputSpec.emplace_back("ITS", "DIGITSMCTR", 0, Lifetime::Timeframe); - outputSpec.emplace_back("ITS", "DIGITSMC2ROF", 0, Lifetime::Timeframe); + return base + "_" + std::to_string(index); +} + +template +template +void DigitReader::setBranchAddress(const std::string& base, Ptr& addr, int layer) +{ + const auto name = getBranchName(base, layer); + if (Int_t ret = mTree->SetBranchAddress(name.c_str(), &addr); ret != 0) { + LOGP(fatal, "failed to set branch address for {} ret={}", name, ret); } - if (useTriggers) { - outputSpec.emplace_back("ITS", "PHYSTRIG", 0, Lifetime::Timeframe); +} + +namespace +{ +template +std::vector makeOutChannels(bool mctruth, bool useCalib) +{ + constexpr o2::header::DataOrigin Origin{N == o2::detectors::DetID::ITS ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; + std::vector outputs; + static constexpr int RLayers = o2::itsmft::DPLAlpideParam::supportsStaggering() ? o2::itsmft::DPLAlpideParam::getNLayers() : 1; + for (int iLayer = 0; iLayer < RLayers; ++iLayer) { + outputs.emplace_back(Origin, "DIGITS", iLayer, Lifetime::Timeframe); + outputs.emplace_back(Origin, "DIGITSROF", iLayer, Lifetime::Timeframe); + if (mctruth) { + outputs.emplace_back(Origin, "DIGITSMC2ROF", iLayer, Lifetime::Timeframe); + outputs.emplace_back(Origin, "DIGITSMCTR", iLayer, Lifetime::Timeframe); + } } + if (useCalib) { + outputs.emplace_back(Origin, "GBTCALIB", 0, Lifetime::Timeframe); + } + outputs.emplace_back(Origin, "PHYSTRIG", 0, Lifetime::Timeframe); + return outputs; +} +} // namespace + +DataProcessorSpec getITSDigitReaderSpec(bool useMC, bool useCalib, bool useTriggers, std::string defname) +{ return DataProcessorSpec{ - "its-digit-reader", - Inputs{}, - outputSpec, - AlgorithmSpec{adaptFromTask(useMC, useCalib)}, - Options{ + .name = "its-digit-reader", + .inputs = Inputs{}, + .outputs = makeOutChannels(useMC, useCalib), + .algorithm = AlgorithmSpec{adaptFromTask(useMC, useCalib)}, + .options = Options{ {"its-digit-infile", VariantType::String, defname, {"Name of the input digit file"}}, {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } DataProcessorSpec getMFTDigitReaderSpec(bool useMC, bool useCalib, bool useTriggers, std::string defname) { - std::vector outputSpec; - outputSpec.emplace_back("MFT", "DIGITS", 0, Lifetime::Timeframe); - outputSpec.emplace_back("MFT", "DIGITSROF", 0, Lifetime::Timeframe); - if (useCalib) { - outputSpec.emplace_back("MFT", "GBTCALIB", 0, Lifetime::Timeframe); - } - if (useMC) { - outputSpec.emplace_back("MFT", "DIGITSMCTR", 0, Lifetime::Timeframe); - outputSpec.emplace_back("MFT", "DIGITSMC2ROF", 0, Lifetime::Timeframe); - } - if (useTriggers) { - outputSpec.emplace_back("MFT", "PHYSTRIG", 0, Lifetime::Timeframe); - } return DataProcessorSpec{ - "mft-digit-reader", - Inputs{}, - outputSpec, - AlgorithmSpec{adaptFromTask(useMC, useCalib)}, - Options{ + .name = "mft-digit-reader", + .inputs = Inputs{}, + .outputs = makeOutChannels(useMC, useCalib), + .algorithm = AlgorithmSpec{adaptFromTask(useMC, useCalib)}, + .options = Options{ {"mft-digit-infile", VariantType::String, defname, {"Name of the input digit file"}}, {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } diff --git a/Detectors/ITSMFT/common/workflow/src/DigitWriterSpec.cxx b/Detectors/ITSMFT/common/workflow/src/DigitWriterSpec.cxx index 3a06d106ceb1f..c4f1e336180c7 100644 --- a/Detectors/ITSMFT/common/workflow/src/DigitWriterSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/DigitWriterSpec.cxx @@ -12,6 +12,9 @@ /// @brief Processor spec for a ROOT file writer for ITSMFT digits #include "ITSMFTWorkflow/DigitWriterSpec.h" +#include "Framework/ConcreteDataMatcher.h" +#include "Framework/DataRef.h" +#include "ITSMFTBase/DPLAlpideParam.h" #include "DPLUtils/MakeRootTreeWriterSpec.h" #include "DataFormatsITSMFT/Digit.h" #include "DataFormatsITSMFT/GBTCalibData.h" @@ -39,14 +42,24 @@ using MCCont = o2::dataformats::ConstMCTruthContainer; /// create the processor spec /// describing a processor receiving digits for ITS/MFT and writing them to file -DataProcessorSpec getDigitWriterSpec(bool mctruth, bool dec, bool calib, o2::header::DataOrigin detOrig, o2::detectors::DetID detId) +template +DataProcessorSpec getDigitWriterSpec(bool mctruth, bool dec, bool calib) { - std::string detStr = o2::detectors::DetID::getName(detId); + static constexpr o2::header::DataOrigin Origin{N == o2::detectors::DetID::ITS ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; + constexpr int NLayers = o2::itsmft::DPLAlpideParam::supportsStaggering() ? o2::itsmft::DPLAlpideParam::getNLayers() : 1; + std::string detStr = o2::detectors::DetID::getName(N); std::string detStrL = dec ? "o2_" : ""; // for decoded digits prepend by o2 detStrL += detStr; std::transform(detStrL.begin(), detStrL.end(), detStrL.begin(), ::tolower); - auto logger = [](std::vector const& inDigits) { - LOG(info) << "RECEIVED DIGITS SIZE " << inDigits.size(); + auto digitSizes = std::make_shared>(); + auto digitSizeGetter = [digitSizes](std::vector const& inDigits, DataRef const& ref) { + auto const* dh = DataRefUtils::getHeader(ref); + (*digitSizes)[dh->subSpecification] = inDigits.size(); + }; + auto rofSizes = std::make_shared>(); + auto rofSizeGetter = [rofSizes](std::vector const& inROFs, DataRef const& ref) { + auto const* dh = DataRefUtils::getHeader(ref); + (*rofSizes)[dh->subSpecification] = inROFs.size(); }; // the callback to be set as hook for custom action when the writer is closed @@ -71,9 +84,11 @@ DataProcessorSpec getDigitWriterSpec(bool mctruth, bool dec, bool calib, o2::hea // handler for labels // This is necessary since we can't store the original label buffer in a ROOT entry -- as is -- if it exceeds a certain size. // We therefore convert it to a special split class. - auto fillLabels = [](TBranch& branch, std::vector const& labelbuffer, DataRef const& /*ref*/) { + auto fillLabels = [digitSizes, rofSizes](TBranch& branch, std::vector const& labelbuffer, DataRef const& ref) { o2::dataformats::ConstMCTruthContainerView labels(labelbuffer); - LOG(info) << "WRITING " << labels.getNElements() << " LABELS "; + auto const* dh = DataRefUtils::getHeader(ref); + auto layer = static_cast(dh->subSpecification); + LOG(info) << "WRITING " << labels.getNElements() << " LABELS FOR " << layer << " WITH " << (*digitSizes)[layer] << " DIGITS IN " << (*rofSizes)[layer] << " ROFS"; o2::dataformats::IOMCTruthContainerView outputcontainer; auto ptr = &outputcontainer; @@ -83,35 +98,56 @@ DataProcessorSpec getDigitWriterSpec(bool mctruth, bool dec, bool calib, o2::hea br->ResetAddress(); }; + auto getIndex = [](DataRef const& ref) -> size_t { + auto const* dh = DataRefUtils::getHeader(ref); + return static_cast(dh->subSpecification); + }; + auto getName = [](std::string base, size_t index) -> std::string { + if constexpr (o2::itsmft::DPLAlpideParam::supportsStaggering()) { + return base += "_" + std::to_string(index); + } + return base; + }; return MakeRootTreeWriterSpec((detStr + "DigitWriter" + (dec ? "_dec" : "")).c_str(), (detStrL + "digits.root").c_str(), - MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Digits tree"}, + MakeRootTreeWriterSpec::TreeAttributes{.name = "o2sim", .title = detStr + " Digits tree"}, MakeRootTreeWriterSpec::CustomClose(finishWriting), - // in case of labels we first read them as std::vector and process them correctly in the fillLabels hook - BranchDefinition>{InputSpec{(detStr + "_digitsMCTR").c_str(), detOrig, "DIGITSMCTR", 0}, - (detStr + "DigitMCTruth").c_str(), - (mctruth ? 1 : 0), fillLabels}, - BranchDefinition>{InputSpec{(detStr + "_digitsMC2ROF").c_str(), detOrig, "DIGITSMC2ROF", 0}, - (detStr + "DigitMC2ROF").c_str(), - (mctruth ? 1 : 0)}, - BranchDefinition>{InputSpec{(detStr + "digits").c_str(), detOrig, "DIGITS", 0}, - (detStr + "Digit").c_str(), - logger}, - BranchDefinition>{InputSpec{(detStr + "calib").c_str(), detOrig, "GBTCALIB", 0}, - (detStr + "Calib").c_str(), - (calib ? 1 : 0)}, - BranchDefinition>{InputSpec{(detStr + "digitsROF").c_str(), detOrig, "DIGITSROF", 0}, - (detStr + "DigitROF").c_str()})(); + BranchDefinition>{InputSpec{detStr + "digits", ConcreteDataTypeMatcher{Origin, "DIGITS"}}, + detStr + "Digit", "digit-branch", + NLayers, + digitSizeGetter, + getIndex, + getName}, + BranchDefinition>{InputSpec{detStr + "digitsROF", ConcreteDataTypeMatcher{Origin, "DIGITSROF"}}, + detStr + "DigitROF", "digit-rof-branch", + NLayers, + rofSizeGetter, + getIndex, + getName}, + BranchDefinition>{InputSpec{detStr + "_digitsMCTR", ConcreteDataTypeMatcher{Origin, "DIGITSMCTR"}}, + detStr + "DigitMCTruth", "digit-mctruth-branch", + (mctruth ? NLayers : 0), + fillLabels, + getIndex, + getName}, + BranchDefinition>{InputSpec{detStr + "_digitsMC2ROF", ConcreteDataTypeMatcher{Origin, "DIGITSMC2ROF"}}, + detStr + "DigitMC2ROF", "digit-mc2rof-branch", + (mctruth ? NLayers : 0), + getIndex, + getName}, + BranchDefinition>{InputSpec{detStr + "calib", ConcreteDataTypeMatcher{Origin, "GBTCALIB"}}, + detStr + "Calib", "digit-calib-branch", + (calib ? 1 : 0)})(); } DataProcessorSpec getITSDigitWriterSpec(bool mctruth, bool dec, bool calib) { - return getDigitWriterSpec(mctruth, dec, calib, o2::header::gDataOriginITS, o2::detectors::DetID::ITS); + return getDigitWriterSpec(mctruth, dec, calib); } DataProcessorSpec getMFTDigitWriterSpec(bool mctruth, bool dec, bool calib) { - return getDigitWriterSpec(mctruth, dec, calib, o2::header::gDataOriginMFT, o2::detectors::DetID::MFT); + return getDigitWriterSpec(mctruth, dec, calib); } } // end namespace itsmft diff --git a/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx index b40e377d58ca2..6809c8dee3f19 100644 --- a/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx @@ -17,12 +17,13 @@ #include "Framework/Lifetime.h" #include "Framework/Task.h" #include "Framework/CCDBParamSpec.h" -#include "Steer/HitProcessingManager.h" // for DigitizationContext +#include "SimulationDataFormat/DigitizationContext.h" #include "DataFormatsITSMFT/Digit.h" #include "DataFormatsITSMFT/NoiseMap.h" #include "DataFormatsITSMFT/TimeDeadMap.h" #include "SimulationDataFormat/ConstMCTruthContainer.h" #include "DetectorsBase/BaseDPLDigitizer.h" +#include "DetectorsRaw/HBFUtils.h" #include "DetectorsCommonDataFormats/DetID.h" #include "DetectorsCommonDataFormats/SimTraits.h" #include "DetectorsCommonDataFormats/DetectorNameConf.h" @@ -36,20 +37,25 @@ #include #include #include +#include using namespace o2::framework; using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType; -namespace o2 -{ -namespace itsmft +namespace o2::itsmft { using namespace o2::base; +template class ITSMFTDPLDigitizerTask : BaseDPLDigitizer { public: + static constexpr o2::detectors::DetID ID{N == o2::detectors::DetID::ITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT}; + static constexpr o2::header::DataOrigin Origin{N == o2::detectors::DetID::ITS ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; + static constexpr int NLayers{o2::itsmft::DPLAlpideParam::getNLayers()}; + using BaseDPLDigitizer::init; + void initDigitizerTask(framework::InitContext& ic) override { mDisableQED = ic.options().get("disable-qed"); @@ -60,121 +66,174 @@ class ITSMFTDPLDigitizerTask : BaseDPLDigitizer if (mFinished) { return; } + mFirstOrbitTF = pc.services().get().firstTForbit; - mID == o2::detectors::DetID::ITS ? updateTimeDependentParams(pc) : updateTimeDependentParams(pc); - std::string detStr = mID.getName(); + const o2::InteractionRecord firstIR(0, mFirstOrbitTF); + updateTimeDependentParams(pc); + + TStopwatch timer; + timer.Start(); + LOG(info) << " CALLING ITS DIGITIZATION "; + // read collision context from input auto context = pc.inputs().get("collisioncontext"); - context->initSimChains(mID, mSimChains); + context->initSimChains(ID, mSimChains); const bool withQED = context->isQEDProvided() && !mDisableQED; auto& timesview = context->getEventRecords(withQED); LOG(info) << "GOT " << timesview.size() << " COLLISSION TIMES"; - LOG(info) << "SIMCHAINS " << mSimChains.size(); + LOG(info) << "SIMCHAINS: " << mSimChains.size(); // if there is nothing to do ... return if (timesview.size() == 0) { return; } - TStopwatch timer; - timer.Start(); - LOG(info) << " CALLING ITS DIGITIZATION "; - mDigitizer.setDigits(&mDigits); - mDigitizer.setROFRecords(&mROFRecords); - mDigitizer.setMCLabels(&mLabels); + uint64_t nDigits{0}; + constexpr uint32_t nLayers = (DPLAlpideParam::supportsStaggering()) ? NLayers : 1; + for (uint32_t iLayer = 0; iLayer < nLayers; ++iLayer) { + const int layer = (DPLAlpideParam::supportsStaggering()) ? iLayer : -1; + mDigitizer.setDigits(&mDigits[iLayer]); + mDigitizer.setROFRecords(&mROFRecords[iLayer]); + mDigitizer.setMCLabels(&mLabels[iLayer]); + mDigitizer.resetROFrameBounds(); + + // digits are directly put into DPL owned resource + auto& digitsAccum = pc.outputs().make>(Output{Origin, "DIGITS", iLayer}); + + // rofs are accumulated first and the copied + const int nROFsPerOrbit = o2::constants::lhc::LHCMaxBunches / DPLAlpideParam::Instance().getROFLengthInBC(iLayer); + const int nROFsTF = nROFsPerOrbit * raw::HBFUtils::Instance().getNOrbitsPerTF(); + mROFRecordsAccum[iLayer].reserve(nROFsTF); + + auto accumulate = [this, &digitsAccum, &iLayer]() { + // accumulate result of single event processing on a specific layer, called after processing every event supplied + // AND after the final flushing via digitizer::fillOutputContainer + if (!mDigits[iLayer].size()) { + return; // no digits were flushed, nothing to accumulate + } + auto ndigAcc = digitsAccum.size(); + std::copy(mDigits[iLayer].begin(), mDigits[iLayer].end(), std::back_inserter(digitsAccum)); + + // fix ROFrecords references on ROF entries + auto nROFRecsOld = mROFRecordsAccum[iLayer].size(); + + for (int i = 0; i < mROFRecords[iLayer].size(); i++) { + auto& rof = mROFRecords[iLayer][i]; + rof.setFirstEntry(ndigAcc + rof.getFirstEntry()); + rof.print(); + + if (mFixMC2ROF[iLayer] < mMC2ROFRecordsAccum[iLayer].size()) { // fix ROFRecord entry in MC2ROF records + for (int m2rid = mFixMC2ROF[iLayer]; m2rid < mMC2ROFRecordsAccum[iLayer].size(); m2rid++) { + // need to register the ROFRecors entry for MC event starting from this entry + auto& mc2rof = mMC2ROFRecordsAccum[iLayer][m2rid]; + if (rof.getROFrame() == mc2rof.minROF) { + mFixMC2ROF[iLayer]++; + mc2rof.rofRecordID = nROFRecsOld + i; + mc2rof.print(); + } + } + } + } + + std::copy(mROFRecords[iLayer].begin(), mROFRecords[iLayer].end(), std::back_inserter(mROFRecordsAccum[iLayer])); + if (mWithMCTruth) { + mLabelsAccum[iLayer].mergeAtBack(mLabels[iLayer]); + } + LOG(info) << "Added " << mDigits[iLayer].size() << " digits:" << iLayer; + // clean containers from already accumulated stuff + mLabels[iLayer].clear(); + mDigits[iLayer].clear(); + mROFRecords[iLayer].clear(); + }; // and accumulate lambda + + const auto& eventParts = context->getEventParts(withQED); + const int64_t bcShift = mDigitizer.getParams().getROFrameBiasInBC(layer); // this accounts the misalignment and the opt. imposed rof delay + // loop over all composite collisions given from context (aka loop over all the interaction records) + for (int collID = 0; collID < timesview.size(); ++collID) { + auto irt = timesview[collID]; + if (irt.toLong() < bcShift) { // due to the ROF misalignment (+opt. delay) the collision would go to negative ROF ID, discard + continue; + } + irt -= bcShift; // account for the ROF start shift + + mDigitizer.setEventTime(irt, layer); + mDigitizer.resetEventROFrames(); // to estimate min/max ROF for this collID + // for each collision, loop over the constituents event and source IDs + // (background signal merging is basically taking place here) + for (const auto& part : eventParts[collID]) { - // digits are directly put into DPL owned resource - auto& digitsAccum = pc.outputs().make>(Output{mOrigin, "DIGITS", 0}); + // get the hits for this event and this source + mHits.clear(); + context->retrieveHits(mSimChains, o2::detectors::SimTraits::DETECTORBRANCHNAMES[ID][0].c_str(), part.sourceID, part.entryID, &mHits); - auto accumulate = [this, &digitsAccum]() { - // accumulate result of single event processing, called after processing every event supplied - // AND after the final flushing via digitizer::fillOutputContainer - if (!mDigits.size()) { - return; // no digits were flushed, nothing to accumulate + if (mHits.size() > 0) { + LOG(debug) << "For collision " << collID << " eventID " << part.entryID << " found " << mHits.size() << " hits "; + mDigitizer.process(&mHits, part.entryID, part.sourceID, layer); // call actual digitization procedure + } + } + mMC2ROFRecordsAccum[iLayer].emplace_back(collID, -1, mDigitizer.getEventROFrameMin(), mDigitizer.getEventROFrameMax()); + accumulate(); } - auto ndigAcc = digitsAccum.size(); - std::copy(mDigits.begin(), mDigits.end(), std::back_inserter(digitsAccum)); - - // fix ROFrecords references on ROF entries - auto nROFRecsOld = mROFRecordsAccum.size(); - - for (int i = 0; i < mROFRecords.size(); i++) { - auto& rof = mROFRecords[i]; - rof.setFirstEntry(ndigAcc + rof.getFirstEntry()); - rof.print(); - - if (mFixMC2ROF < mMC2ROFRecordsAccum.size()) { // fix ROFRecord entry in MC2ROF records - for (int m2rid = mFixMC2ROF; m2rid < mMC2ROFRecordsAccum.size(); m2rid++) { - // need to register the ROFRecors entry for MC event starting from this entry - auto& mc2rof = mMC2ROFRecordsAccum[m2rid]; - if (rof.getROFrame() == mc2rof.minROF) { - mFixMC2ROF++; - mc2rof.rofRecordID = nROFRecsOld + i; - mc2rof.print(); - } + mDigitizer.fillOutputContainer(0xffffffff, layer); + accumulate(); + nDigits += digitsAccum.size(); + + // here we have all digits and labels and we can send them to consumer (aka snapshot it onto output) + // ensure that the rof output is continuous + if (nROFsTF != mROFRecordsAccum[iLayer].size()) { + // it can happen that in the digitization rofs without contributing hits are skipped + // however downstream consumers of the clusters cannot know apriori the time structure + // the cluster rofs do not account for the bias so it will start always at BC=0 + std::vector expDigitRofVec(nROFsTF); + for (int iROF{0}; iROF < nROFsTF; ++iROF) { + auto& rof = expDigitRofVec[iROF]; + int orb = iROF * DPLAlpideParam::Instance().getROFLengthInBC(iLayer) / o2::constants::lhc::LHCMaxBunches + mFirstOrbitTF; + int bc = iROF * DPLAlpideParam::Instance().getROFLengthInBC(iLayer) % o2::constants::lhc::LHCMaxBunches; + o2::InteractionRecord ir(bc, orb); + rof.setBCData(ir); + rof.setROFrame(iROF); + rof.setNEntries(0); + rof.setFirstEntry(-1); + } + uint32_t prevEntry{0}; + for (const auto& rof : mROFRecordsAccum[iLayer]) { + const auto& ir = rof.getBCData(); + const auto irToFirst = ir - firstIR; + const int irROF = irToFirst.toLong() / DPLAlpideParam::Instance().getROFLengthInBC(iLayer); + auto& expROF = expDigitRofVec[irROF]; + expROF.setFirstEntry(rof.getFirstEntry()); + expROF.setNEntries(rof.getNEntries()); + if (expROF.getBCData() != rof.getBCData()) { + LOGP(fatal, "detected mismatch between expected ROF:{} and received ROF:{}", expROF.asString(), rof.asString()); + } + } + int prevFirst{0}; + for (auto& rof : expDigitRofVec) { + if (rof.getFirstEntry() < 0) { + rof.setFirstEntry(prevFirst); } + prevFirst = rof.getFirstEntry(); } + pc.outputs().snapshot(Output{Origin, "DIGITSROF", iLayer}, expDigitRofVec); + } else { + pc.outputs().snapshot(Output{Origin, "DIGITSROF", iLayer}, mROFRecordsAccum[iLayer]); } - - std::copy(mROFRecords.begin(), mROFRecords.end(), std::back_inserter(mROFRecordsAccum)); if (mWithMCTruth) { - mLabelsAccum.mergeAtBack(mLabels); - } - LOG(info) << "Added " << mDigits.size() << " digits "; - // clean containers from already accumulated stuff - mLabels.clear(); - mDigits.clear(); - mROFRecords.clear(); - }; // and accumulate lambda - - auto& eventParts = context->getEventParts(withQED); - int bcShift = mDigitizer.getParams().getROFrameBiasInBC(); - // loop over all composite collisions given from context (aka loop over all the interaction records) - for (int collID = 0; collID < timesview.size(); ++collID) { - auto irt = timesview[collID]; - if (irt.toLong() < bcShift) { // due to the ROF misalignment the collision would go to negative ROF ID, discard - continue; + pc.outputs().snapshot(Output{Origin, "DIGITSMC2ROF", iLayer}, mMC2ROFRecordsAccum[iLayer]); + auto& sharedlabels = pc.outputs().make>(Output{Origin, "DIGITSMCTR", iLayer}); + mLabelsAccum[iLayer].flatten_to(sharedlabels); + // free space of existing label containers + mLabels[iLayer].clear_andfreememory(); + mLabelsAccum[iLayer].clear_andfreememory(); } - irt -= bcShift; // account for the ROF start shift - - mDigitizer.setEventTime(irt); - mDigitizer.resetEventROFrames(); // to estimate min/max ROF for this collID - // for each collision, loop over the constituents event and source IDs - // (background signal merging is basically taking place here) - for (auto& part : eventParts[collID]) { - - // get the hits for this event and this source - mHits.clear(); - context->retrieveHits(mSimChains, o2::detectors::SimTraits::DETECTORBRANCHNAMES[mID][0].c_str(), part.sourceID, part.entryID, &mHits); - - if (mHits.size() > 0) { - LOG(debug) << "For collision " << collID << " eventID " << part.entryID - << " found " << mHits.size() << " hits "; - mDigitizer.process(&mHits, part.entryID, part.sourceID); // call actual digitization procedure - } - } - mMC2ROFRecordsAccum.emplace_back(collID, -1, mDigitizer.getEventROFrameMin(), mDigitizer.getEventROFrameMax()); - accumulate(); } - mDigitizer.fillOutputContainer(); - accumulate(); - - // here we have all digits and labels and we can send them to consumer (aka snapshot it onto output) - - pc.outputs().snapshot(Output{mOrigin, "DIGITSROF", 0}, mROFRecordsAccum); - if (mWithMCTruth) { - pc.outputs().snapshot(Output{mOrigin, "DIGITSMC2ROF", 0}, mMC2ROFRecordsAccum); - auto& sharedlabels = pc.outputs().make>(Output{mOrigin, "DIGITSMCTR", 0}); - mLabelsAccum.flatten_to(sharedlabels); - // free space of existing label containers - mLabels.clear_andfreememory(); - mLabelsAccum.clear_andfreememory(); - } - LOG(info) << mID.getName() << ": Sending ROMode= " << mROMode << " to GRPUpdater"; - pc.outputs().snapshot(Output{mOrigin, "ROMode", 0}, mROMode); + + LOG(info) << ID.getName() << ": Sending ROMode= " << mROMode << " to GRPUpdater"; + pc.outputs().snapshot(Output{Origin, "ROMode", 0}, mROMode); timer.Stop(); LOG(info) << "Digitization took " << timer.CpuTime() << "s"; + LOG(info) << "Produced " << nDigits << " digits"; // we should be only called once; tell DPL that this process is ready to exit pc.services().get().readyToQuit(QuitRequest::Me); @@ -184,18 +243,18 @@ class ITSMFTDPLDigitizerTask : BaseDPLDigitizer void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) { - if (matcher == ConcreteDataMatcher(mOrigin, "NOISEMAP", 0)) { - LOG(info) << mID.getName() << " noise map updated"; + if (matcher == ConcreteDataMatcher(Origin, "NOISEMAP", 0)) { + LOG(info) << ID.getName() << " noise map updated"; mDigitizer.setNoiseMap((const o2::itsmft::NoiseMap*)obj); return; } - if (matcher == ConcreteDataMatcher(mOrigin, "DEADMAP", 0)) { - LOG(info) << mID.getName() << " static dead map updated"; + if (matcher == ConcreteDataMatcher(Origin, "DEADMAP", 0)) { + LOG(info) << ID.getName() << " static dead map updated"; mDeadMap = (o2::itsmft::NoiseMap*)obj; mDigitizer.setDeadChannelsMap(mDeadMap); return; } - if (matcher == ConcreteDataMatcher(mOrigin, "TimeDeadMap", 0)) { + if (matcher == ConcreteDataMatcher(Origin, "TimeDeadMap", 0)) { o2::itsmft::TimeDeadMap* timedeadmap = (o2::itsmft::TimeDeadMap*)obj; if (!timedeadmap->isDefault()) { timedeadmap->decodeMap(mFirstOrbitTF, *mDeadMap, true); @@ -204,30 +263,25 @@ class ITSMFTDPLDigitizerTask : BaseDPLDigitizer } mTimeDeadMapUpdated = true; mDigitizer.setDeadChannelsMap(mDeadMap); - LOG(info) << mID.getName() << " time-dependent dead map updated"; + LOG(info) << ID.getName() << " time-dependent dead map updated"; } else { - LOG(info) << mID.getName() << " time-dependent dead map is default/empty"; + LOG(info) << ID.getName() << " time-dependent dead map is default/empty"; } return; } - if (matcher == ConcreteDataMatcher(mOrigin, "ALPIDEPARAM", 0)) { - LOG(info) << mID.getName() << " Alpide param updated"; - if (mID == o2::detectors::DetID::ITS) { - const auto& par = o2::itsmft::DPLAlpideParam::Instance(); - par.printKeyValues(); - } else { - const auto& par = o2::itsmft::DPLAlpideParam::Instance(); - par.printKeyValues(); - } + if (matcher == ConcreteDataMatcher(Origin, "ALPIDEPARAM", 0)) { + LOG(info) << ID.getName() << " Alpide param updated"; + const auto& par = o2::itsmft::DPLAlpideParam::Instance(); + par.printKeyValues(); return; } - if (matcher == ConcreteDataMatcher(mOrigin, "ALPIDERESPVbb0", 0)) { - LOG(info) << mID.getName() << " loaded AlpideResponseData for Vbb=0V"; + if (matcher == ConcreteDataMatcher(Origin, "ALPIDERESPVbb0", 0)) { + LOG(info) << ID.getName() << " loaded AlpideResponseData for Vbb=0V"; mDigitizer.setAlpideResponse((o2::itsmft::AlpideSimResponse*)obj, 0); } - if (matcher == ConcreteDataMatcher(mOrigin, "ALPIDERESPVbbM3", 0)) { - LOG(info) << mID.getName() << " loaded AlpideResponseData for Vbb=-3V"; + if (matcher == ConcreteDataMatcher(Origin, "ALPIDERESPVbbM3", 0)) { + LOG(info) << ID.getName() << " loaded AlpideResponseData for Vbb=-3V"; mDigitizer.setAlpideResponse((o2::itsmft::AlpideSimResponse*)obj, 1); } } @@ -235,20 +289,19 @@ class ITSMFTDPLDigitizerTask : BaseDPLDigitizer protected: ITSMFTDPLDigitizerTask(bool mctruth = true) : BaseDPLDigitizer(InitServices::FIELD | InitServices::GEOM), mWithMCTruth(mctruth) {} - template void updateTimeDependentParams(ProcessingContext& pc) { - std::string detstr(o2::detectors::DetID::getName(DETID)); + std::string detstr(o2::detectors::DetID::getName(ID)); pc.inputs().get(detstr + "_noise"); pc.inputs().get(detstr + "_dead"); // TODO: the code should run even if this object does not exist. Or: create default object pc.inputs().get(detstr + "_time_dead"); - pc.inputs().get*>(detstr + "_alppar"); + pc.inputs().get*>(detstr + "_alppar"); pc.inputs().get(detstr + "_alpiderespvbb0"); pc.inputs().get(detstr + "_alpiderespvbbm3"); - auto& dopt = o2::itsmft::DPLDigitizerParam::Instance(); - auto& aopt = o2::itsmft::DPLAlpideParam::Instance(); + auto& dopt = o2::itsmft::DPLDigitizerParam::Instance(); + auto& aopt = o2::itsmft::DPLAlpideParam::Instance(); auto& digipar = mDigitizer.getParams(); digipar.setContinuous(dopt.continuous); digipar.setROFrameBiasInBC(aopt.roFrameBiasInBC); @@ -272,15 +325,29 @@ class ITSMFTDPLDigitizerTask : BaseDPLDigitizer digipar.setIBVbb(dopt.IBVbb); digipar.setOBVbb(dopt.OBVbb); digipar.setVbb(dopt.Vbb); + // staggering parameters + if constexpr (o2::itsmft::DPLAlpideParam::supportsStaggering()) { + const bool withStag = aopt.withStaggering(); + for (int iLayer{0}; iLayer < o2::itsmft::DPLAlpideParam::getNLayers(); ++iLayer) { + const int nLayer = (withStag) ? iLayer : -1; + auto frameNS = aopt.getROFLengthInBC(nLayer) * o2::constants::lhc::LHCBunchSpacingNS; + digipar.addROFrameLayerLengthInBC(aopt.getROFLengthInBC(nLayer)); + // NOTE: the rof delay looks from the digitizer like an additional bias + digipar.addROFrameLayerBiasInBC(aopt.getROFBiasInBC(nLayer) + aopt.getROFDelayInBC(nLayer)); + digipar.addStrobeDelay(aopt.strobeDelay); + digipar.addStrobeLength(aopt.strobeLengthCont > 0 ? aopt.strobeLengthCont : frameNS - aopt.strobeDelay); + digipar.setROFrameLength(aopt.getROFLengthInBC(nLayer) * o2::constants::lhc::LHCBunchSpacingNS, iLayer); + } + } mROMode = digipar.isContinuous() ? o2::parameters::GRPObject::CONTINUOUS : o2::parameters::GRPObject::PRESENT; - LOG(info) << mID.getName() << " simulated in " + LOG(info) << detstr << " simulated in " << ((mROMode == o2::parameters::GRPObject::CONTINUOUS) ? "CONTINUOUS" : "TRIGGERED") << " RO mode"; // configure digitizer o2::itsmft::GeometryTGeo* geom = nullptr; - if (mID == o2::detectors::DetID::ITS) { + if constexpr (N == o2::detectors::DetID::ITS) { geom = o2::its::GeometryTGeo::Instance(); } else { geom = o2::mft::GeometryTGeo::Instance(); @@ -294,81 +361,61 @@ class ITSMFTDPLDigitizerTask : BaseDPLDigitizer bool mFinished = false; bool mDisableQED = false; unsigned long mFirstOrbitTF = 0x0; - o2::detectors::DetID mID; - o2::header::DataOrigin mOrigin = o2::header::gDataOriginInvalid; o2::itsmft::Digitizer mDigitizer; - std::vector mDigits; - std::vector mROFRecords; - std::vector mROFRecordsAccum; + std::array, NLayers> mDigits; + std::array, NLayers> mROFRecords; + std::array, NLayers> mROFRecordsAccum; std::vector mHits; std::vector* mHitsP = &mHits; - o2::dataformats::MCTruthContainer mLabels; - o2::dataformats::MCTruthContainer mLabelsAccum; - std::vector mMC2ROFRecordsAccum; + std::array, NLayers> mLabels; + std::array, NLayers> mLabelsAccum; + std::array, NLayers> mMC2ROFRecordsAccum; std::vector mSimChains; o2::itsmft::NoiseMap* mDeadMap = nullptr; - int mFixMC2ROF = 0; // 1st entry in mc2rofRecordsAccum to be fixed for ROFRecordID + std::array mFixMC2ROF{}; // 1st entry in mc2rofRecordsAccum to be fixed for ROFRecordID bool mTimeDeadMapUpdated = false; o2::parameters::GRPObject::ROMode mROMode = o2::parameters::GRPObject::PRESENT; // readout mode }; //_______________________________________________ -class ITSDPLDigitizerTask : public ITSMFTDPLDigitizerTask +class ITSDPLDigitizerTask : public ITSMFTDPLDigitizerTask { public: - // FIXME: origin should be extractable from the DetID, the problem is 3d party header dependencies - static constexpr o2::detectors::DetID::ID DETID = o2::detectors::DetID::ITS; - static constexpr o2::header::DataOrigin DETOR = o2::header::gDataOriginITS; - ITSDPLDigitizerTask(bool mctruth = true) : ITSMFTDPLDigitizerTask(mctruth) - { - mID = DETID; - mOrigin = DETOR; - } + ITSDPLDigitizerTask(bool mctruth = true) : ITSMFTDPLDigitizerTask(mctruth) {} }; -constexpr o2::detectors::DetID::ID ITSDPLDigitizerTask::DETID; -constexpr o2::header::DataOrigin ITSDPLDigitizerTask::DETOR; - //_______________________________________________ -class MFTDPLDigitizerTask : public ITSMFTDPLDigitizerTask +class MFTDPLDigitizerTask : public ITSMFTDPLDigitizerTask { public: - // FIXME: origina should be extractable from the DetID, the problem is 3d party header dependencies - static constexpr o2::detectors::DetID::ID DETID = o2::detectors::DetID::MFT; - static constexpr o2::header::DataOrigin DETOR = o2::header::gDataOriginMFT; - MFTDPLDigitizerTask(bool mctruth) : ITSMFTDPLDigitizerTask(mctruth) - { - mID = DETID; - mOrigin = DETOR; - } + MFTDPLDigitizerTask(bool mctruth = true) : ITSMFTDPLDigitizerTask(mctruth) {} }; -constexpr o2::detectors::DetID::ID MFTDPLDigitizerTask::DETID; -constexpr o2::header::DataOrigin MFTDPLDigitizerTask::DETOR; - +namespace +{ +template std::vector makeOutChannels(o2::header::DataOrigin detOrig, bool mctruth) { std::vector outputs; - outputs.emplace_back(detOrig, "DIGITS", 0, Lifetime::Timeframe); - outputs.emplace_back(detOrig, "DIGITSROF", 0, Lifetime::Timeframe); - if (mctruth) { - outputs.emplace_back(detOrig, "DIGITSMC2ROF", 0, Lifetime::Timeframe); - outputs.emplace_back(detOrig, "DIGITSMCTR", 0, Lifetime::Timeframe); + constexpr uint32_t nLayers = (DPLAlpideParam::supportsStaggering()) ? DPLAlpideParam::getNLayers() : 1; + for (uint32_t iLayer = 0; iLayer < nLayers; ++iLayer) { + outputs.emplace_back(detOrig, "DIGITS", iLayer, Lifetime::Timeframe); + outputs.emplace_back(detOrig, "DIGITSROF", iLayer, Lifetime::Timeframe); + if (mctruth) { + outputs.emplace_back(detOrig, "DIGITSMC2ROF", iLayer, Lifetime::Timeframe); + outputs.emplace_back(detOrig, "DIGITSMCTR", iLayer, Lifetime::Timeframe); + } } outputs.emplace_back(detOrig, "ROMode", 0, Lifetime::Timeframe); return outputs; } +} // namespace DataProcessorSpec getITSDigitizerSpec(int channel, bool mctruth) { - std::string detStr = o2::detectors::DetID::getName(ITSDPLDigitizerTask::DETID); - auto detOrig = ITSDPLDigitizerTask::DETOR; - std::stringstream parHelper; - parHelper << "Params as " << o2::itsmft::DPLDigitizerParam::getParamName().data() << ".=value;... with" - << o2::itsmft::DPLDigitizerParam::Instance() - << "\n or " << o2::itsmft::DPLAlpideParam::getParamName().data() << ".=value;... with" - << o2::itsmft::DPLAlpideParam::Instance(); + std::string detStr = o2::detectors::DetID::getName(ITSDPLDigitizerTask::ID); + auto detOrig = ITSDPLDigitizerTask::Origin; std::vector inputs; inputs.emplace_back("collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast(channel), Lifetime::Timeframe); inputs.emplace_back("ITS_noise", "ITS", "NOISEMAP", 0, Lifetime::Condition, ccdbParamSpec("ITS/Calib/NoiseMap")); @@ -377,19 +424,18 @@ DataProcessorSpec getITSDigitizerSpec(int channel, bool mctruth) inputs.emplace_back("ITS_alppar", "ITS", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/AlpideParam")); inputs.emplace_back("ITS_alpiderespvbb0", "ITS", "ALPIDERESPVbb0", 0, Lifetime::Condition, ccdbParamSpec("ITSMFT/Calib/ALPIDEResponseVbb0")); inputs.emplace_back("ITS_alpiderespvbbm3", "ITS", "ALPIDERESPVbbM3", 0, Lifetime::Condition, ccdbParamSpec("ITSMFT/Calib/ALPIDEResponseVbbM3")); - - return DataProcessorSpec{(detStr + "Digitizer").c_str(), - inputs, makeOutChannels(detOrig, mctruth), - AlgorithmSpec{adaptFromTask(mctruth)}, - Options{ + return DataProcessorSpec{.name = detStr + "Digitizer", + .inputs = inputs, + .outputs = makeOutChannels(detOrig, mctruth), + .algorithm = AlgorithmSpec{adaptFromTask(mctruth)}, + .options = Options{ {"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}}}}; } DataProcessorSpec getMFTDigitizerSpec(int channel, bool mctruth) { - std::string detStr = o2::detectors::DetID::getName(MFTDPLDigitizerTask::DETID); - auto detOrig = MFTDPLDigitizerTask::DETOR; - std::stringstream parHelper; + std::string detStr = o2::detectors::DetID::getName(MFTDPLDigitizerTask::ID); + auto detOrig = MFTDPLDigitizerTask::Origin; std::vector inputs; inputs.emplace_back("collisioncontext", "SIM", "COLLISIONCONTEXT", static_cast(channel), Lifetime::Timeframe); inputs.emplace_back("MFT_noise", "MFT", "NOISEMAP", 0, Lifetime::Condition, ccdbParamSpec("MFT/Calib/NoiseMap")); @@ -398,15 +444,12 @@ DataProcessorSpec getMFTDigitizerSpec(int channel, bool mctruth) inputs.emplace_back("MFT_alppar", "MFT", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("MFT/Config/AlpideParam")); inputs.emplace_back("MFT_alpiderespvbb0", "MFT", "ALPIDERESPVbb0", 0, Lifetime::Condition, ccdbParamSpec("ITSMFT/Calib/ALPIDEResponseVbb0")); inputs.emplace_back("MFT_alpiderespvbbm3", "MFT", "ALPIDERESPVbbM3", 0, Lifetime::Condition, ccdbParamSpec("ITSMFT/Calib/ALPIDEResponseVbbM3")); - parHelper << "Params as " << o2::itsmft::DPLDigitizerParam::getParamName().data() << ".=value;... with" - << o2::itsmft::DPLDigitizerParam::Instance() - << " or " << o2::itsmft::DPLAlpideParam::getParamName().data() << ".=value;... with" - << o2::itsmft::DPLAlpideParam::Instance(); - return DataProcessorSpec{(detStr + "Digitizer").c_str(), - inputs, makeOutChannels(detOrig, mctruth), - AlgorithmSpec{adaptFromTask(mctruth)}, - Options{{"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}}}}; + return DataProcessorSpec{.name = detStr + "Digitizer", + .inputs = inputs, + .outputs = makeOutChannels(detOrig, mctruth), + .algorithm = AlgorithmSpec{adaptFromTask(mctruth)}, + .options = Options{{"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}}}}; } -} // end namespace itsmft -} // end namespace o2 +} // namespace o2::itsmft + // end namespace o2 From b18b96ab60f829b2cb853b6a4553a47167948165 Mon Sep 17 00:00:00 2001 From: Roman Lietava Date: Sun, 25 Jan 2026 10:38:46 +0100 Subject: [PATCH 112/234] Ctpdev: task for populating BK with ctp config/scalers (#14993) * dev: code for repopulating BK with old configs/scalers * clang * fixes * fixes * clang * fix --- Detectors/CTP/workflowScalers/CMakeLists.txt | 8 + .../CTPWorkflowScalers/ctpCCDBManager.h | 5 +- .../CTP/workflowScalers/src/ctp-bk-write.cxx | 170 ++++++++++++++++++ .../workflowScalers/src/ctpCCDBManager.cxx | 27 +++ 4 files changed, 208 insertions(+), 2 deletions(-) create mode 100644 Detectors/CTP/workflowScalers/src/ctp-bk-write.cxx diff --git a/Detectors/CTP/workflowScalers/CMakeLists.txt b/Detectors/CTP/workflowScalers/CMakeLists.txt index a31774ac66d69..f02a7f33e2abd 100644 --- a/Detectors/CTP/workflowScalers/CMakeLists.txt +++ b/Detectors/CTP/workflowScalers/CMakeLists.txt @@ -34,3 +34,11 @@ o2_add_executable( SOURCES src/ctp-ccdb-orbit.cxx PUBLIC_LINK_LIBRARIES O2::DataFormatsCTP Boost::program_options) +o2_add_executable( + bk-write + COMPONENT_NAME ctp + SOURCES src/ctp-bk-write.cxx + PUBLIC_LINK_LIBRARIES O2::DataFormatsCTP + O2::CTPWorkflowScalers + AliceO2::BookkeepingApi + Boost::program_options) diff --git a/Detectors/CTP/workflowScalers/include/CTPWorkflowScalers/ctpCCDBManager.h b/Detectors/CTP/workflowScalers/include/CTPWorkflowScalers/ctpCCDBManager.h index 4237ad4501fcc..df2aa79d18697 100644 --- a/Detectors/CTP/workflowScalers/include/CTPWorkflowScalers/ctpCCDBManager.h +++ b/Detectors/CTP/workflowScalers/include/CTPWorkflowScalers/ctpCCDBManager.h @@ -31,8 +31,9 @@ class ctpCCDBManager int saveOrbitReset(long timeStamp); int saveCtpCfg(uint32_t runNumber, long timeStamp); static CTPConfiguration getConfigFromCCDB(long timestamp, std::string run, bool& ok); - static CTPConfiguration getConfigFromCCDB(long timestamp, std::string run); - CTPRunScalers getScalersFromCCDB(long timestamp, std::string, bool& ok); + CTPConfiguration getConfigFromCCDB(long timestamp, std::string run); + CTPRunScalers getScalersFromCCDB(long timestamp, std::string run, bool& ok); + static CTPRunScalers getScalersFromCCDB(long timestamp, std::string, std::string path, bool& ok); static void setCCDBHost(std::string host) { mCCDBHost = host; }; static void setQCDBHost(std::string host) { mQCDBHost = host; }; void setCtpCfgDir(std::string& ctpcfgdir) { mCtpCfgDir = ctpcfgdir; }; diff --git a/Detectors/CTP/workflowScalers/src/ctp-bk-write.cxx b/Detectors/CTP/workflowScalers/src/ctp-bk-write.cxx new file mode 100644 index 0000000000000..8460c07dcc896 --- /dev/null +++ b/Detectors/CTP/workflowScalers/src/ctp-bk-write.cxx @@ -0,0 +1,170 @@ +// 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. + +// 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. + +// example to run: +// +#include +#include +#include +#include +#include "CommonUtils/StringUtils.h" +#include +#include "CTPWorkflowScalers/ctpCCDBManager.h" +#include "BookkeepingApi/BkpClientFactory.h" +#include "BookkeepingApi/BkpClient.h" +#include +#include +#include +#include +namespace bpo = boost::program_options; +// +// Test in the lab +// o2-ctp-bk-write -r 37 -s 1 -c 1 --ccdb='http://acsl-ccdb.cern.ch:8083' -b 'acsl-aliecs.cern.ch:4001' -t 1753185071753 +// +int main(int argc, char** argv) +{ + const std::string testCCDB = "http://ccdb-test.cern.ch:8080"; + // std::string prodCCDB = "http://o2-ccdb.internal"; + const std::string aliceCCDB = "http://alice-ccdb.cern.ch"; + bpo::variables_map vm; + bpo::options_description opt_general("Usage:\n " + std::string(argv[0]) + + " Write ctp config or scalers to BK\n"); + bpo::options_description opt_hidden(""); + bpo::options_description opt_all; + bpo::positional_options_description opt_pos; + try { + auto add_option = opt_general.add_options(); + add_option("help,h", "Print this help message"); + add_option("input-file,f", bpo::value()->default_value("none"), "input file name, none - do not read file"); + add_option("bkhost,b", bpo::value()->default_value("none"), "bk web address"); + add_option("ccdb", bpo::value()->default_value("alice"), "choose databse: test- test ccdb; prod - production ccdb; alice - alice ccdb; else ccdb parameter"); + add_option("run-number,r", bpo::value()->default_value(0), "run number"); + add_option("timestamp,t", bpo::value()->default_value(0), "timestamp; if 0 timestamp is calulated inside this code"); + add_option("cfg,c", bpo::value()->default_value(0), "Do cfg"); + add_option("scalers,s", bpo::value()->default_value(0), "Do scalers"); + // + opt_all.add(opt_general).add(opt_hidden); + bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm); + if (vm.count("help")) { + std::cout << opt_general << std::endl; + exit(0); + } + bpo::notify(vm); + } catch (bpo::error& e) { + std::cerr << "ERROR: " << e.what() << std::endl + << std::endl; + std::cerr << opt_general << std::endl; + exit(1); + } catch (std::exception& e) { + std::cerr << e.what() << ", application will now exit" << std::endl; + exit(2); + } + uint64_t timestamp = vm["timestamp"].as(); + // + int ret = 0; + std::vector runs; + int32_t run = vm["run-number"].as(); + std::cout << "run:" << run << std::endl; + if (run) { + std::cout << "pushing" << std::endl; + runs.push_back(std::to_string(run)); + } + // read input file + std::string filename = vm["input-file"].as(); + if (filename != "none") { + std::ifstream file(filename); + if (!file.is_open()) { + LOG(fatal) << "Cannot open file:" << filename << std::endl; + } else { + std::string line; + while (std::getline(file, line)) { + std::cout << line << "\n"; + std::vector tokens = o2::utils::Str::tokenize(line, ' '); + // int run = std::stoi(tokens[0]); + runs.push_back(tokens[0]); + } + } + } + bool cfg = vm["cfg"].as(); + bool scalers = vm["scalers"].as(); + std::cout << "Doing: cfg:" << cfg << " scal:" << scalers << std::endl; + if (cfg || scalers) { + std::string bkhost = vm["bkhost"].as(); + std::unique_ptr mBKClient = o2::bkp::api::BkpClientFactory::create(bkhost); + // get from ccdb + std::string ccdbAddress; + if (vm["ccdb"].as() == "prod") { + // ccdbAddress = prodCCDB; + } else if (vm["ccdb"].as() == "test") { + ccdbAddress = testCCDB; + } else if (vm["ccdb"].as() == "alice") { + ccdbAddress = aliceCCDB; + } else { + ccdbAddress = vm["ccdb"].as(); + } + o2::ctp::ctpCCDBManager::setCCDBHost(ccdbAddress); + std::cout << "CCDB: " << vm["ccdb"].as() << " " << ccdbAddress << std::endl; + std::map metadata; + for (auto const& run : runs) { + metadata["runNumber"] = run; + bool ok; + int runNumber = std::stoi(run); + auto ctpcfg = o2::ctp::ctpCCDBManager::getConfigFromCCDB(timestamp, run, ok); + + if (cfg) { + std::string ctpcfgstr = ctpcfg.getConfigString(); + try { + mBKClient->run()->setRawCtpTriggerConfiguration(runNumber, ctpcfgstr); + } catch (std::runtime_error& error) { + std::cerr << "An error occurred: " << error.what() << std::endl; + // return 1; + } + LOG(info) << "Run BK:" << run << " CFG:" << cfg; + } + if (scalers) { + auto ctpcnts = o2::ctp::ctpCCDBManager::getScalersFromCCDB(timestamp, run, "CTP/Calib/Scalers", ok); + ctpcnts.convertRawToO2(); + std::vector clsinds = ctpcnts.getClassIndexes(); + long ts = ctpcnts.getTimeLimit().second; + int i = 0; + for (auto const& ind : clsinds) { + std::array cntsbk = ctpcnts.getIntegralForClass(i); + std::string clsname = ctpcfg.getClassNameFromHWIndex(cntsbk[0]); + try { + mBKClient->ctpTriggerCounters()->createOrUpdateForRun(runNumber, clsname, ts, cntsbk[1], cntsbk[2], cntsbk[3], cntsbk[4], cntsbk[5], cntsbk[6]); + std::cout << runNumber << " clsname: " << cntsbk[0] << " " << clsname << " t:" << ts << " cnts:" << cntsbk[1] << " " << cntsbk[2] << " " << cntsbk[3] << " " << cntsbk[4] << " " << cntsbk[5] << " " << cntsbk[6] << std::endl; + ; + + } catch (std::runtime_error& error) { + std::cerr << "An error occurred: " << error.what() << std::endl; + // return 1; + } + LOG(debug) << "Run BK scalers ok"; + i++; + } + } + } + // add to bk + } + std::cout << "o2-ctp-bk-write done" << std::endl; + return ret; +} diff --git a/Detectors/CTP/workflowScalers/src/ctpCCDBManager.cxx b/Detectors/CTP/workflowScalers/src/ctpCCDBManager.cxx index df75b21c2effd..74d4a905c93e2 100644 --- a/Detectors/CTP/workflowScalers/src/ctpCCDBManager.cxx +++ b/Detectors/CTP/workflowScalers/src/ctpCCDBManager.cxx @@ -204,10 +204,16 @@ int ctpCCDBManager::saveCtpCfg(uint32_t runNumber, long timeStart) } CTPConfiguration ctpCCDBManager::getConfigFromCCDB(long timestamp, std::string run, bool& ok) { + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); mgr.setURL(mCCDBHost); std::map metadata; // can be empty metadata["runNumber"] = run; + if (timestamp == 0) { + // Timestamp + auto soreor = mgr.getRunDuration(std::stoi(run)); + timestamp = (soreor.second - soreor.first) / 2 + soreor.first; + } auto ctpconfigdb = mgr.getSpecific(CCDBPathCTPConfig, timestamp, metadata); if (ctpconfigdb == nullptr) { LOG(info) << "CTP config not in database, timestamp:" << timestamp; @@ -245,3 +251,24 @@ CTPRunScalers ctpCCDBManager::getScalersFromCCDB(long timestamp, std::string run } return *ctpscalers; } +CTPRunScalers ctpCCDBManager::getScalersFromCCDB(long timestamp, std::string run, std::string path, bool& ok) +{ + auto& mgr = o2::ccdb::BasicCCDBManager::instance(); + mgr.setURL(mCCDBHost); + std::map metadata; // can be empty + metadata["runNumber"] = run; + if (timestamp == 0) { + // Timestamp + auto soreor = mgr.getRunDuration(std::stoi(run)); + timestamp = (soreor.second - soreor.first) / 2 + soreor.first; + } + auto ctpscalers = mgr.getSpecific(path, timestamp, metadata); + if (ctpscalers == nullptr) { + LOG(info) << "CTPRunScalers not in database, timestamp:" << timestamp; + ok = 0; + } else { + // ctpscalers->printStream(std::cout); + ok = 1; + } + return *ctpscalers; +} \ No newline at end of file From b33261326dc4203ba6e537df64e04b4bdb3716d5 Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Fri, 23 Jan 2026 14:55:22 +0100 Subject: [PATCH 113/234] Implement AO2D file checks for full_system_test Performed during ASYNC stage, where the AO2D is created --- prodtests/full_system_test.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/prodtests/full_system_test.sh b/prodtests/full_system_test.sh index bf235a500cd8b..6408588d46e68 100755 --- a/prodtests/full_system_test.sh +++ b/prodtests/full_system_test.sh @@ -295,6 +295,25 @@ for STAGE in $STAGES; do # boolean flag indicating if workflow completed successfully at all RC=$? SUCCESS=0 + # Check AOD production for ASYNC stage + if [[ "$STAGE" = "ASYNC" ]]; then + if [[ -f "AO2D.root" ]]; then + aod_size=`stat -c%s AO2D.root` + if [[ $aod_size -gt 0 ]]; then + echo "AO2D file produced: AO2D.root (size: ${aod_size} bytes)" + echo "aod_size_${STAGE},${TAG} value=${aod_size}" >> ${METRICFILE} + else + echo "ERROR: AO2D file (AO2D.root) exists but is empty" + echo "aod_size_${STAGE},${TAG} value=0" >> ${METRICFILE} + exit 1 + fi + else + echo "ERROR: AO2D file (AO2D.root) was not produced in ASYNC stage" + echo "aod_size_${STAGE},${TAG} value=0" >> ${METRICFILE} + exit 1 + fi + fi + [[ -f "${logfile}_done" ]] && [[ "$RC" = 0 ]] && SUCCESS=1 echo "success_${STAGE},${TAG} value=${SUCCESS}" >> ${METRICFILE} From 1fba29618f1f469fb918c725234f1d9f45dfc183 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Mon, 26 Jan 2026 10:23:20 +0100 Subject: [PATCH 114/234] DPL Analysis: modernize and cleanup some code (#14975) --- .../AnalysisSupport/src/AODReaderHelpers.cxx | 55 ++++------- Framework/Core/include/Framework/ASoA.h | 1 + .../Core/include/Framework/Expressions.h | 2 +- Framework/Core/src/ASoA.cxx | 96 +++++++++---------- Framework/Core/src/AnalysisHelpers.cxx | 37 +++---- Framework/Core/src/ArrowSupport.cxx | 26 ++--- Framework/Core/src/ArrowTableSlicingCache.cxx | 6 +- Framework/Core/src/Expressions.cxx | 4 +- Framework/Core/src/WorkflowHelpers.cxx | 74 +++++++------- 9 files changed, 129 insertions(+), 172 deletions(-) diff --git a/Framework/AnalysisSupport/src/AODReaderHelpers.cxx b/Framework/AnalysisSupport/src/AODReaderHelpers.cxx index 485f3fa69edad..4c1c065000186 100644 --- a/Framework/AnalysisSupport/src/AODReaderHelpers.cxx +++ b/Framework/AnalysisSupport/src/AODReaderHelpers.cxx @@ -37,7 +37,7 @@ struct Buildable { std::vector records; std::shared_ptr outputSchema; - Buildable(InputSpec const& spec) + explicit Buildable(InputSpec const& spec) : binding{spec.binding} { auto&& [origin_, description_, version_] = DataSpecUtils::asConcreteDataMatcher(spec); @@ -58,9 +58,8 @@ struct Buildable { } outputSchema = std::make_shared([](std::vector const& recs) { std::vector> fields; - for (auto& r : recs) { - fields.push_back(r.field()); - } + fields.reserve(recs.size()); + std::ranges::transform(recs, std::back_inserter(fields), [](auto& r) { return r.field(); }); return fields; }(records)) ->WithMetadata(std::make_shared(std::vector{std::string{"label"}}, std::vector{std::string{binding}})); @@ -87,19 +86,12 @@ AlgorithmSpec AODReaderHelpers::indexBuilderCallback(ConfigContext const& /*ctx* { return AlgorithmSpec::InitCallback{[](InitContext& ic) { auto const& requested = ic.services().get().requestedIDXs; - std::vector buildables; - for (auto const& i : requested) { - buildables.emplace_back(i); - } std::vector builders; - for (auto& b : buildables) { - builders.push_back(b.createBuilder()); - } + builders.reserve(requested.size()); + std::ranges::transform(requested, std::back_inserter(builders), [](auto const& i) { return Buildable{i}.createBuilder(); }); return [builders](ProcessingContext& pc) mutable { auto outputs = pc.outputs(); - for (auto& builder : builders) { - outputs.adopt(Output{builder.origin, builder.description, builder.version}, builder.materialize(pc)); - } + std::ranges::for_each(builders, [&pc, &outputs](auto& builder) { outputs.adopt(Output{builder.origin, builder.description, builder.version}, builder.materialize(pc)); }); }; }}; } @@ -119,7 +111,7 @@ struct Spawnable { header::DataDescription description; header::DataHeader::SubSpecificationType version; - Spawnable(InputSpec const& spec) + explicit Spawnable(InputSpec const& spec) : binding{spec.binding} { auto&& [origin_, description_, version_] = DataSpecUtils::asConcreteDataMatcher(spec); @@ -144,16 +136,19 @@ struct Spawnable { iws.str(json); schemas.emplace_back(ArrowJSONHelpers::read(iws)); } - for (auto const& i : spec.metadata | views::filter_string_params_starts_with("input:") | std::ranges::views::transform([](auto const& param) { - return DataSpecUtils::fromMetadataString(param.defaultValue.template get()); - })) { - matchers.emplace_back(std::get(i.matcher)); - } + std::ranges::transform(spec.metadata | + views::filter_string_params_starts_with("input:") | + std::ranges::views::transform( + [](auto const& param) { + return DataSpecUtils::fromMetadataString(param.defaultValue.template get()); + }), + std::back_inserter(matchers), [](auto const& i) { return std::get(i.matcher); }); std::vector> fields; - for (auto& s : schemas) { - std::copy(s->fields().begin(), s->fields().end(), std::back_inserter(fields)); - } + std::ranges::for_each(schemas, + [&fields](auto const& s) { + std::ranges::copy(s->fields(), std::back_inserter(fields)); + }); inputSchema = std::make_shared(fields); expressions = expressions::materializeProjectors(projectors, inputSchema, outputSchema->fields()); @@ -194,20 +189,12 @@ AlgorithmSpec AODReaderHelpers::aodSpawnerCallback(ConfigContext const& /*ctx*/) { return AlgorithmSpec::InitCallback{[](InitContext& ic) { auto const& requested = ic.services().get().spawnerInputs; - std::vector spawnables; - for (auto const& i : requested) { - spawnables.emplace_back(i); - } std::vector spawners; - for (auto& s : spawnables) { - spawners.push_back(s.createMaker()); - } - + spawners.reserve(requested.size()); + std::ranges::transform(requested, std::back_inserter(spawners), [](auto const& i) { return Spawnable{i}.createMaker(); }); return [spawners](ProcessingContext& pc) mutable { auto outputs = pc.outputs(); - for (auto& spawner : spawners) { - outputs.adopt(Output{spawner.origin, spawner.description, spawner.version}, spawner.materialize(pc)); - } + std::ranges::for_each(spawners, [&pc, &outputs](auto& spawner) { outputs.adopt(Output{spawner.origin, spawner.description, spawner.version}, spawner.materialize(pc)); }); }; }}; } diff --git a/Framework/Core/include/Framework/ASoA.h b/Framework/Core/include/Framework/ASoA.h index ec02c7e47132b..4fd35e0dc5065 100644 --- a/Framework/Core/include/Framework/ASoA.h +++ b/Framework/Core/include/Framework/ASoA.h @@ -1283,6 +1283,7 @@ struct TableIterator : IP, C... { }; struct ArrowHelpers { + static std::shared_ptr joinTables(std::vector>&& tables); static std::shared_ptr joinTables(std::vector>&& tables, std::span labels); static std::shared_ptr joinTables(std::vector>&& tables, std::span labels); static std::shared_ptr concatTables(std::vector>&& tables); diff --git a/Framework/Core/include/Framework/Expressions.h b/Framework/Core/include/Framework/Expressions.h index 0be19954f1faa..c5f50311a7d19 100644 --- a/Framework/Core/include/Framework/Expressions.h +++ b/Framework/Core/include/Framework/Expressions.h @@ -712,7 +712,7 @@ std::shared_ptr createProjectorHelper(size_t nColumns, expre std::shared_ptr schema, std::vector> const& fields); -std::vector> materializeProjectors(std::vector const& projectors, std::shared_ptr const& inputSchema, std::vector> outputFields); +std::vector> materializeProjectors(std::vector const& projectors, std::shared_ptr const& inputSchema, std::vector> const& outputFields); template std::shared_ptr createProjectors(framework::pack, std::vector> const& fields, gandiva::SchemaPtr schema) diff --git a/Framework/Core/src/ASoA.cxx b/Framework/Core/src/ASoA.cxx index 6a846c3d45b6c..1c73b257f81e4 100644 --- a/Framework/Core/src/ASoA.cxx +++ b/Framework/Core/src/ASoA.cxx @@ -62,71 +62,71 @@ SelectionVector sliceSelection(std::span const& mSelectedRows, in auto start_iterator = std::lower_bound(mSelectedRows.begin(), mSelectedRows.end(), start); auto stop_iterator = std::lower_bound(start_iterator, mSelectedRows.end(), end); SelectionVector slicedSelection{start_iterator, stop_iterator}; - std::transform(slicedSelection.begin(), slicedSelection.end(), slicedSelection.begin(), - [&start](int64_t idx) { - return idx - static_cast(start); - }); + std::ranges::transform(slicedSelection.begin(), slicedSelection.end(), slicedSelection.begin(), + [&start](int64_t idx) { + return idx - static_cast(start); + }); return slicedSelection; } -std::shared_ptr ArrowHelpers::joinTables(std::vector>&& tables, std::span labels) +std::shared_ptr ArrowHelpers::joinTables(std::vector>&& tables) { - if (tables.size() == 1) { - return tables[0]; - } - for (auto i = 0U; i < tables.size() - 1; ++i) { - if (tables[i]->num_rows() != tables[i + 1]->num_rows()) { - throw o2::framework::runtime_error_f("Tables %s and %s have different sizes (%d vs %d) and cannot be joined!", - labels[i], labels[i + 1], tables[i]->num_rows(), tables[i + 1]->num_rows()); - } - } std::vector> fields; std::vector> columns; - - for (auto& t : tables) { - auto tf = t->fields(); - std::copy(tf.begin(), tf.end(), std::back_inserter(fields)); - } - - auto schema = std::make_shared(fields); - - if (tables[0]->num_rows() != 0) { - for (auto& t : tables) { - auto tc = t->columns(); - std::copy(tc.begin(), tc.end(), std::back_inserter(columns)); + bool notEmpty = (tables[0]->num_rows() != 0); + std::ranges::for_each(tables, [&fields, &columns, notEmpty](auto const& t) { + std::ranges::copy(t->fields(), std::back_inserter(fields)); + if (notEmpty) { + std::ranges::copy(t->columns(), std::back_inserter(columns)); } - } + }); + auto schema = std::make_shared(fields); return arrow::Table::Make(schema, columns); } -std::shared_ptr ArrowHelpers::joinTables(std::vector>&& tables, std::span labels) +namespace +{ +template + requires(std::same_as) +auto makeString(T const& str) +{ + return str.c_str(); +} +template + requires(std::same_as) +auto makeString(T const& str) +{ + return str; +} + +template +void canNotJoin(std::vector> const& tables, std::span labels) { - if (tables.size() == 1) { - return tables[0]; - } for (auto i = 0U; i < tables.size() - 1; ++i) { if (tables[i]->num_rows() != tables[i + 1]->num_rows()) { throw o2::framework::runtime_error_f("Tables %s and %s have different sizes (%d vs %d) and cannot be joined!", - labels[i].c_str(), labels[i + 1].c_str(), tables[i]->num_rows(), tables[i + 1]->num_rows()); + makeString(labels[i]), makeString(labels[i + 1]), tables[i]->num_rows(), tables[i + 1]->num_rows()); } } - std::vector> fields; - std::vector> columns; +} +} // namespace - for (auto& t : tables) { - auto tf = t->fields(); - std::copy(tf.begin(), tf.end(), std::back_inserter(fields)); +std::shared_ptr ArrowHelpers::joinTables(std::vector>&& tables, std::span labels) +{ + if (tables.size() == 1) { + return tables[0]; } + canNotJoin(tables, labels); + return joinTables(std::forward>>(tables)); +} - auto schema = std::make_shared(fields); - - if (tables[0]->num_rows() != 0) { - for (auto& t : tables) { - auto tc = t->columns(); - std::copy(tc.begin(), tc.end(), std::back_inserter(columns)); - } +std::shared_ptr ArrowHelpers::joinTables(std::vector>&& tables, std::span labels) +{ + if (tables.size() == 1) { + return tables[0]; } - return arrow::Table::Make(schema, columns); + canNotJoin(tables, labels); + return joinTables(std::forward>>(tables)); } std::shared_ptr ArrowHelpers::concatTables(std::vector>&& tables) @@ -135,7 +135,6 @@ std::shared_ptr ArrowHelpers::concatTables(std::vector> columns; - assert(tables.size() > 1); std::vector> resultFields = tables[0]->schema()->fields(); auto compareFields = [](std::shared_ptr const& f1, std::shared_ptr const& f2) { // Let's do this with stable sorting. @@ -165,13 +164,12 @@ std::shared_ptr ArrowHelpers::concatTables(std::vector(chunks)); } - auto result = arrow::Table::Make(std::make_shared(resultFields), columns); - return result; + return arrow::Table::Make(std::make_shared(resultFields), columns); } arrow::ChunkedArray* getIndexFromLabel(arrow::Table* table, std::string_view label) { - auto field = std::find_if(table->schema()->fields().begin(), table->schema()->fields().end(), [&](std::shared_ptr const& f) { + auto field = std::ranges::find_if(table->schema()->fields(), [&](std::shared_ptr const& f) { auto caseInsensitiveCompare = [](const std::string_view& str1, const std::string& str2) { return std::ranges::equal( str1, str2, diff --git a/Framework/Core/src/AnalysisHelpers.cxx b/Framework/Core/src/AnalysisHelpers.cxx index f2ecb2d68ce28..b7eac692d3859 100644 --- a/Framework/Core/src/AnalysisHelpers.cxx +++ b/Framework/Core/src/AnalysisHelpers.cxx @@ -46,14 +46,12 @@ void IndexBuilder::resetBuilders(std::vector& bui std::shared_ptr IndexBuilder::materialize(std::vector& builders, std::vector>&& tables, std::vector const& records, std::shared_ptr const& schema, bool exclusive) { auto size = tables[0]->num_rows(); - if (builders.empty()) { + if (O2_BUILTIN_UNLIKELY(builders.empty())) { builders = makeBuilders(std::move(tables), records); } else { resetBuilders(builders, std::move(tables)); } - std::vector finds; - finds.resize(builders.size()); for (int64_t counter = 0; counter < size; ++counter) { int64_t idx = -1; if (std::get(builders[0].builder).keyIndex == nullptr) { @@ -61,29 +59,19 @@ std::shared_ptr IndexBuilder::materialize(std::vector(builders[0].builder).keyIndex->valueAt(counter); } - for (auto i = 0U; i < builders.size(); ++i) { - finds[i] = builders[i].find(idx); - } - if (exclusive) { - if (std::none_of(finds.begin(), finds.end(), [](bool const x) { return x == false; })) { - builders[0].fill(counter); - for (auto i = 1U; i < builders.size(); ++i) { - builders[i].fill(idx); - } - } - } else { + + bool found = true; + std::ranges::for_each(builders, [&idx, &found](auto& builder) { found &= builder.find(idx); }); + + if (!exclusive || found) { builders[0].fill(counter); - for (auto i = 1U; i < builders.size(); ++i) { - builders[i].fill(idx); - } + std::ranges::for_each(builders.begin() + 1, builders.end(), [&idx](auto& builder) { builder.fill(idx); }); } } std::vector> arrays; arrays.reserve(builders.size()); - for (auto& builder : builders) { - arrays.push_back(builder.result()); - } + std::ranges::transform(builders, std::back_inserter(arrays), [](auto& builder) { return builder.result(); }); return arrow::Table::Make(schema, arrays); } @@ -142,9 +130,7 @@ std::shared_ptr spawnerHelper(std::shared_ptr const& } arrays.reserve(nColumns); - for (auto i = 0U; i < nColumns; ++i) { - arrays.push_back(std::make_shared(chunks[i])); - } + std::ranges::transform(chunks, std::back_inserter(arrays), [](auto&& chunk) { return std::make_shared(chunk); }); return arrow::Table::Make(newSchema, arrays); } @@ -188,9 +174,8 @@ std::string serializeIndexRecords(std::vector& irs) std::vector> extractSources(ProcessingContext& pc, std::vector const& matchers) { std::vector> tables; - for (auto const& matcher : matchers) { - tables.emplace_back(pc.inputs().get(matcher)->asArrowTable()); - } + tables.reserve(matchers.size()); + std::ranges::transform(matchers, std::back_inserter(tables), [&pc](auto const& matcher) { return pc.inputs().get(matcher)->asArrowTable(); }); return tables; } diff --git a/Framework/Core/src/ArrowSupport.cxx b/Framework/Core/src/ArrowSupport.cxx index 95e763343671a..60277dfc38a74 100644 --- a/Framework/Core/src/ArrowSupport.cxx +++ b/Framework/Core/src/ArrowSupport.cxx @@ -531,13 +531,7 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() dh->dataOrigin.str, dh->dataDescription.str); continue; } - bool forwarded = false; - for (auto const& forward : ctx.services().get().forwards) { - if (DataSpecUtils::match(forward.matcher, *dh)) { - forwarded = true; - break; - } - } + bool forwarded = std::ranges::any_of(ctx.services().get().forwards, [&dh](auto const& forward) { return DataSpecUtils::match(forward.matcher, *dh); }); if (forwarded) { O2_SIGNPOST_EVENT_EMIT(rate_limiting, sid, "offer", "Message %{public}.4s/%{public}.16s is forwarded so we are not returning its memory.", @@ -584,11 +578,11 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() } }, .adjustTopology = [](WorkflowSpecNode& node, ConfigContext const& ctx) { auto& workflow = node.specs; - auto spawner = std::find_if(workflow.begin(), workflow.end(), [](DataProcessorSpec const& spec) { return spec.name == "internal-dpl-aod-spawner"; }); - auto analysisCCDB = std::find_if(workflow.begin(), workflow.end(), [](DataProcessorSpec const& spec) { return spec.name == "internal-dpl-aod-ccdb"; }); - auto builder = std::find_if(workflow.begin(), workflow.end(), [](DataProcessorSpec const& spec) { return spec.name == "internal-dpl-aod-index-builder"; }); - auto reader = std::find_if(workflow.begin(), workflow.end(), [](DataProcessorSpec const& spec) { return spec.name == "internal-dpl-aod-reader"; }); - auto writer = std::find_if(workflow.begin(), workflow.end(), [](DataProcessorSpec const& spec) { return spec.name == "internal-dpl-aod-writer"; }); + auto spawner = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-spawner"); }); + auto analysisCCDB = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-ccdb"); }); + auto builder = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-index-builder"); }); + auto reader = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-reader"); }); + auto writer = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-writer"); }); auto& dec = ctx.services().get(); dec.requestedAODs.clear(); dec.requestedDYNs.clear(); @@ -626,8 +620,8 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() views::partial_match_filter(header::DataOrigin{"DYN"}) | sinks::append_to{dec.providedDYNs}; } - std::sort(dec.requestedDYNs.begin(), dec.requestedDYNs.end(), inputSpecLessThan); - std::sort(dec.providedDYNs.begin(), dec.providedDYNs.end(), outputSpecLessThan); + std::ranges::sort(dec.requestedDYNs, inputSpecLessThan); + std::ranges::sort(dec.providedDYNs, outputSpecLessThan); dec.spawnerInputs.clear(); dec.requestedDYNs | views::filter_not_matching(dec.providedDYNs) | @@ -646,8 +640,8 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() d.inputs | views::partial_match_filter(header::DataOrigin{"ATIM"}) | sinks::update_input_list{dec.requestedTIMs}; d.outputs | views::partial_match_filter(header::DataOrigin{"ATIM"}) | sinks::append_to{dec.providedTIMs}; } - std::sort(dec.requestedTIMs.begin(), dec.requestedTIMs.end(), inputSpecLessThan); - std::sort(dec.providedTIMs.begin(), dec.providedTIMs.end(), outputSpecLessThan); + std::ranges::sort(dec.requestedTIMs, inputSpecLessThan); + std::ranges::sort(dec.providedTIMs, outputSpecLessThan); // Use ranges::to> in C++23... dec.analysisCCDBInputs.clear(); dec.requestedTIMs | views::filter_not_matching(dec.providedTIMs) | sinks::append_to{dec.analysisCCDBInputs}; diff --git a/Framework/Core/src/ArrowTableSlicingCache.cxx b/Framework/Core/src/ArrowTableSlicingCache.cxx index 634c51f71f5a6..5162c698a1d66 100644 --- a/Framework/Core/src/ArrowTableSlicingCache.cxx +++ b/Framework/Core/src/ArrowTableSlicingCache.cxx @@ -210,7 +210,7 @@ std::pair ArrowTableSlicingCache::getCachePos(const Entry& bindingKey int ArrowTableSlicingCache::getCachePosSortedFor(Entry const& bindingKey) const { - auto locate = std::find(bindingsKeys.begin(), bindingsKeys.end(), bindingKey); + auto locate = std::ranges::find(bindingsKeys, bindingKey); if (locate != bindingsKeys.end()) { return std::distance(bindingsKeys.begin(), locate); } @@ -219,7 +219,7 @@ int ArrowTableSlicingCache::getCachePosSortedFor(Entry const& bindingKey) const int ArrowTableSlicingCache::getCachePosUnsortedFor(Entry const& bindingKey) const { - auto locate_unsorted = std::find(bindingsKeysUnsorted.begin(), bindingsKeysUnsorted.end(), bindingKey); + auto locate_unsorted = std::ranges::find(bindingsKeysUnsorted, bindingKey); if (locate_unsorted != bindingsKeysUnsorted.end()) { return std::distance(bindingsKeysUnsorted.begin(), locate_unsorted); } @@ -275,7 +275,7 @@ void ArrowTableSlicingCache::validateOrder(Entry const& bindingKey, const std::s } auto column = o2::framework::GetColumnByNameCI(input, key); auto array0 = static_cast>(column->chunk(0)->data()); - int32_t prev = 0; + int32_t prev; int32_t cur = array0.Value(0); int32_t lastNeg = cur < 0 ? cur : 0; int32_t lastPos = cur < 0 ? -1 : cur; diff --git a/Framework/Core/src/Expressions.cxx b/Framework/Core/src/Expressions.cxx index 43143f781ddf4..02a862d30032b 100644 --- a/Framework/Core/src/Expressions.cxx +++ b/Framework/Core/src/Expressions.cxx @@ -1348,11 +1348,11 @@ OpNode Parser::opFromToken(std::string const& token) return OpNode{static_cast(std::distance(mapping.begin(), locate))}; } -std::vector> materializeProjectors(std::vector const& projectors, std::shared_ptr const& inputSchema, std::vector> outputFields) +std::vector> materializeProjectors(std::vector const& projectors, std::shared_ptr const& inputSchema, std::vector> const& outputFields) { std::vector> expressions; int i = 0; - for (auto& p : projectors) { + for (auto const& p : projectors) { expressions.push_back( expressions::makeExpression( expressions::createExpressionTree( diff --git a/Framework/Core/src/WorkflowHelpers.cxx b/Framework/Core/src/WorkflowHelpers.cxx index fd9099e1aa24e..ff1ff1f4cf13d 100644 --- a/Framework/Core/src/WorkflowHelpers.cxx +++ b/Framework/Core/src/WorkflowHelpers.cxx @@ -100,7 +100,7 @@ std::vector // which have the current node as incoming. // nextEdges will contain all the edges which are not related // to the current node. - for (auto& ei : remainingEdgesIndex) { + for (auto const& ei : remainingEdgesIndex) { if (*(edgeIn + ei * stride) == node.index) { nextVertex.insert({*(edgeOut + ei * stride), node.layer + 1}); } else { @@ -112,7 +112,7 @@ std::vector // Of all the vertices which have node as incoming, // check if there is any other incoming node. std::set hasPredecessors; - for (auto& ei : remainingEdgesIndex) { + for (auto const& ei : remainingEdgesIndex) { for (auto& m : nextVertex) { if (m.index == *(edgeOut + ei * stride)) { hasPredecessors.insert({m.index, m.layer}); @@ -240,7 +240,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext for (size_t wi = 0; wi < workflow.size(); ++wi) { auto& processor = workflow[wi]; auto name = processor.name; - auto hash = runtime_hash(name.c_str()); + uint32_t hash = runtime_hash(name.c_str()); dec.outTskMap.push_back({hash, name}); std::string prefix = "internal-dpl-"; @@ -252,8 +252,8 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext processor.options.push_back(ConfigParamSpec{"end-value-enumeration", VariantType::Int64, -1ll, {"final value for the enumeration"}}); processor.options.push_back(ConfigParamSpec{"step-value-enumeration", VariantType::Int64, 1ll, {"step between one value and the other"}}); } - bool hasTimeframeInputs = std::any_of(processor.inputs.begin(), processor.inputs.end(), [](auto const& input) { return input.lifetime == Lifetime::Timeframe; }); - bool hasTimeframeOutputs = std::any_of(processor.outputs.begin(), processor.outputs.end(), [](auto const& output) { return output.lifetime == Lifetime::Timeframe; }); + bool hasTimeframeInputs = std::ranges::any_of(processor.inputs, [](auto const& input) { return input.lifetime == Lifetime::Timeframe; }); + bool hasTimeframeOutputs = std::ranges::any_of(processor.outputs, [](auto const& output) { return output.lifetime == Lifetime::Timeframe; }); // A timeframeSink consumes timeframes without creating new // timeframe data. @@ -261,10 +261,9 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext if (rateLimitingIPCID != -1) { if (timeframeSink && processor.name.find("internal-dpl-injected-dummy-sink") == std::string::npos) { O2_SIGNPOST_ID_GENERATE(sid, workflow_helpers); - uint32_t hash = runtime_hash(processor.name.c_str()); bool hasMatch = false; ConcreteDataMatcher summaryMatcher = ConcreteDataMatcher{"DPL", "SUMMARY", static_cast(hash)}; - auto summaryOutput = std::find_if(processor.outputs.begin(), processor.outputs.end(), [&summaryMatcher](auto const& output) { return DataSpecUtils::match(output, summaryMatcher); }); + auto summaryOutput = std::ranges::find_if(processor.outputs, [&summaryMatcher](auto const& output) { return DataSpecUtils::match(output, summaryMatcher); }); if (summaryOutput != processor.outputs.end()) { O2_SIGNPOST_EVENT_EMIT(workflow_helpers, sid, "output enumeration", "%{public}s already there in %{public}s", DataSpecUtils::describe(*summaryOutput).c_str(), processor.name.c_str()); @@ -283,7 +282,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext switch (input.lifetime) { case Lifetime::Timer: { auto concrete = DataSpecUtils::asConcreteDataMatcher(input); - auto hasOption = std::any_of(processor.options.begin(), processor.options.end(), [&input](auto const& option) { return (option.name == "period-" + input.binding); }); + auto hasOption = std::ranges::any_of(processor.options, [&input](auto const& option) { return (option.name == "period-" + input.binding); }); if (hasOption == false) { processor.options.push_back(ConfigParamSpec{"period-" + input.binding, VariantType::Int, 1000, {"period of the timer in milliseconds"}}); } @@ -299,7 +298,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext } break; case Lifetime::Condition: { requestedCCDBs.emplace_back(input); - if ((hasConditionOption == false) && std::none_of(processor.options.begin(), processor.options.end(), [](auto const& option) { return (option.name.compare("condition-backend") == 0); })) { + if ((hasConditionOption == false) && std::ranges::none_of(processor.options, [](auto const& option) { return (option.name.compare("condition-backend") == 0); })) { processor.options.emplace_back(ConfigParamSpec{"condition-backend", VariantType::String, defaultConditionBackend(), {"URL for CCDB"}}); processor.options.emplace_back(ConfigParamSpec{"condition-timestamp", VariantType::Int64, 0ll, {"Force timestamp for CCDB lookup"}}); hasConditionOption = true; @@ -307,7 +306,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext } break; case Lifetime::OutOfBand: { auto concrete = DataSpecUtils::asConcreteDataMatcher(input); - auto hasOption = std::any_of(processor.options.begin(), processor.options.end(), [&input](auto const& option) { return (option.name == "out-of-band-channel-name-" + input.binding); }); + auto hasOption = std::ranges::any_of(processor.options, [&input](auto const& option) { return (option.name == "out-of-band-channel-name-" + input.binding); }); if (hasOption == false) { processor.options.push_back(ConfigParamSpec{"out-of-band-channel-name-" + input.binding, VariantType::String, "out-of-band", {"channel to listen for out of band data"}}); } @@ -333,7 +332,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext } } - std::stable_sort(timer.outputs.begin(), timer.outputs.end(), [](OutputSpec const& a, OutputSpec const& b) { return *DataSpecUtils::getOptionalSubSpec(a) < *DataSpecUtils::getOptionalSubSpec(b); }); + std::ranges::stable_sort(timer.outputs, [](OutputSpec const& a, OutputSpec const& b) { return *DataSpecUtils::getOptionalSubSpec(a) < *DataSpecUtils::getOptionalSubSpec(b); }); for (auto& output : processor.outputs) { if (DataSpecUtils::partialMatch(output, AODOrigins)) { @@ -344,7 +343,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext dec.providedTIMs.emplace_back(output); } else if (DataSpecUtils::partialMatch(output, header::DataOrigin{"ATSK"})) { dec.providedOutputObjHist.emplace_back(output); - auto it = std::find_if(dec.outObjHistMap.begin(), dec.outObjHistMap.end(), [&](auto&& x) { return x.id == hash; }); + auto it = std::ranges::find_if(dec.outObjHistMap, [&](auto&& x) { return x.id == hash; }); if (it == dec.outObjHistMap.end()) { dec.outObjHistMap.push_back({hash, {output.binding.value}}); } else { @@ -359,10 +358,10 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext auto inputSpecLessThan = [](InputSpec const& lhs, InputSpec const& rhs) { return DataSpecUtils::describe(lhs) < DataSpecUtils::describe(rhs); }; auto outputSpecLessThan = [](OutputSpec const& lhs, OutputSpec const& rhs) { return DataSpecUtils::describe(lhs) < DataSpecUtils::describe(rhs); }; - std::sort(dec.requestedDYNs.begin(), dec.requestedDYNs.end(), inputSpecLessThan); - std::sort(dec.requestedTIMs.begin(), dec.requestedTIMs.end(), inputSpecLessThan); - std::sort(dec.providedDYNs.begin(), dec.providedDYNs.end(), outputSpecLessThan); - std::sort(dec.providedTIMs.begin(), dec.providedTIMs.end(), outputSpecLessThan); + std::ranges::sort(dec.requestedDYNs, inputSpecLessThan); + std::ranges::sort(dec.requestedTIMs, inputSpecLessThan); + std::ranges::sort(dec.providedDYNs, outputSpecLessThan); + std::ranges::sort(dec.providedTIMs, outputSpecLessThan); DataProcessorSpec indexBuilder{ "internal-dpl-aod-index-builder", @@ -389,8 +388,8 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext AnalysisSupportHelpers::addMissingOutputsToSpawner({}, dec.spawnerInputs, dec.requestedAODs, aodSpawner); AnalysisSupportHelpers::addMissingOutputsToReader(dec.providedAODs, dec.requestedAODs, aodReader); - std::sort(requestedCCDBs.begin(), requestedCCDBs.end(), inputSpecLessThan); - std::sort(providedCCDBs.begin(), providedCCDBs.end(), outputSpecLessThan); + std::ranges::sort(requestedCCDBs, inputSpecLessThan); + std::ranges::sort(providedCCDBs, outputSpecLessThan); AnalysisSupportHelpers::addMissingOutputsToReader(providedCCDBs, requestedCCDBs, ccdbBackend); std::vector extraSpecs; @@ -412,7 +411,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext // add the reader if (aodReader.outputs.empty() == false) { - auto mctracks2aod = std::find_if(workflow.begin(), workflow.end(), [](auto const& x) { return x.name == "mctracks-to-aod"; }); + auto mctracks2aod = std::ranges::find_if(workflow, [](auto const& x) { return x.name == "mctracks-to-aod"; }); if (mctracks2aod == workflow.end()) { // add normal reader aodReader.outputs.emplace_back(OutputSpec{"TFN", "TFNumber"}); @@ -440,22 +439,22 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext auto& dstf = std::get(matcher.matcher); // Check if any of the provided outputs is a DISTSTF // Check if any of the requested inputs is for a 0xccdb message - bool providesDISTSTF = std::any_of(workflow.begin(), workflow.end(), - [&matcher](auto const& dp) { - return std::any_of(dp.outputs.begin(), dp.outputs.end(), [&matcher](auto const& output) { - return DataSpecUtils::match(matcher, output); - }); - }); + bool providesDISTSTF = std::ranges::any_of(workflow, + [&matcher](auto const& dp) { + return std::any_of(dp.outputs.begin(), dp.outputs.end(), [&matcher](auto const& output) { + return DataSpecUtils::match(matcher, output); + }); + }); // If there is no CCDB requested, but we still ask for a FLP/DISTSUBTIMEFRAME/0xccdb // we add to the first data processor which has no inputs (apart from // enumerations / timers) the responsibility to provide the DISTSUBTIMEFRAME - bool requiresDISTSUBTIMEFRAME = std::any_of(workflow.begin(), workflow.end(), - [&dstf](auto const& dp) { - return std::any_of(dp.inputs.begin(), dp.inputs.end(), [&dstf](auto const& input) { - return DataSpecUtils::match(input, dstf); - }); - }); + bool requiresDISTSUBTIMEFRAME = std::ranges::any_of(workflow, + [&dstf](auto const& dp) { + return std::any_of(dp.inputs.begin(), dp.inputs.end(), [&dstf](auto const& input) { + return DataSpecUtils::match(input, dstf); + }); + }); // We find the first device which has either just enumerations or // just timers, and we will add the DISTSUBTIMEFRAME to it. @@ -560,7 +559,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext auto fileSink = AnalysisSupportHelpers::getGlobalAODSink(ctx); extraSpecs.push_back(fileSink); - auto it = std::find_if(dec.outputsInputs.begin(), dec.outputsInputs.end(), [](InputSpec& spec) -> bool { + auto it = std::ranges::find_if(dec.outputsInputs, [](InputSpec& spec) -> bool { return DataSpecUtils::partialMatch(spec, o2::header::DataOrigin("TFN")); }); size_t ii = std::distance(dec.outputsInputs.begin(), it); @@ -694,15 +693,8 @@ void WorkflowHelpers::adjustTopology(WorkflowSpec& workflow, ConfigContext const } if (distSTFCount > 0) { - bool found = false; for (auto& spec : workflow) { - for (auto& output : spec.outputs) { - if (DataSpecUtils::match(output, ConcreteDataMatcher{"FLP", "DISTSUBTIMEFRAME", 0})) { - found = true; - break; - } - } - if (found) { + if (std::ranges::any_of(spec.outputs, [](auto const& output) { return DataSpecUtils::match(output, ConcreteDataMatcher{"FLP", "DISTSUBTIMEFRAME", 0}); })) { for (unsigned int i = 1; i < distSTFCount; ++i) { spec.outputs.emplace_back(OutputSpec{ConcreteDataMatcher{"FLP", "DISTSUBTIMEFRAME", i}, Lifetime::Timeframe}); } @@ -1005,7 +997,7 @@ std::tuple, std::vector> WorkflowHelpers::analyzeOu input.binding = (snprintf(buf, 63, "output_%zu_%zu", output.workflowId, output.id), buf); // make sure that entries are unique - if (std::find(results.begin(), results.end(), input) == results.end()) { + if (std::ranges::find(results, input) == results.end()) { results.emplace_back(input); isDangling.emplace_back(matched == false); } From 7cc3f1c550e70f8c6b919c7168f505ee13f75dc5 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Mon, 26 Jan 2026 11:22:10 +0100 Subject: [PATCH 115/234] DPL: move snapshot code to use concepts Should be faster to compile and have better debug information. It will also work seamlessly for gsl::span (assuming you have ms_gsl 4.2.1) and std::span. --- .../Core/include/Framework/DataAllocator.h | 243 ++++++++++-------- .../include/Framework/SerializationMethods.h | 13 +- 2 files changed, 143 insertions(+), 113 deletions(-) diff --git a/Framework/Core/include/Framework/DataAllocator.h b/Framework/Core/include/Framework/DataAllocator.h index 287513ec85845..ed9a31ca2857c 100644 --- a/Framework/Core/include/Framework/DataAllocator.h +++ b/Framework/Core/include/Framework/DataAllocator.h @@ -1,4 +1,4 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// Copyright 2019-2026 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. // @@ -29,9 +29,9 @@ #include "Headers/DataHeader.h" #include -#include #include +#include #include #include #include @@ -127,6 +127,10 @@ template concept VectorOfMessageableTypes = is_specialization_v && is_messageable::value; +template +concept ContiguousMessageablesRange = std::ranges::contiguous_range && + is_messageable::value; + /// This allocator is responsible to make sure that the messages created match /// the provided spec and that depending on how many pipelined reader we /// have, messages get created on the channel for the reader of the current @@ -296,8 +300,9 @@ class DataAllocator /// /// Supported types: /// - messageable types (trivially copyable, non-polymorphic - /// - std::vector of messageable types - /// - std::vector of pointers of messageable type + /// - contiguous_range of messageable types + /// - random_access_ranges of pointers of messageable type + /// - sized range of messageable type /// - types with ROOT dictionary and implementing the ROOT ClassDef interface /// /// Note: for many use cases, especially for the messageable types, the `make` interface @@ -308,116 +313,140 @@ class DataAllocator /// Use @a ROOTSerialized type wrapper to force ROOT serialization. Same applies to /// types which do not implement the ClassDef interface but have a dictionary. template + requires(!std::ranges::contiguous_range && is_messageable::value) + void snapshot(const Output& spec, T const& object) + { + return snapshot(spec, std::span(&object, &object + 1)); + } + + void snapshot(const Output& spec, std::string_view const& object) + { + return snapshot(spec, std::span(object.data(), object.size())); + } + + // This is for snapshotting a range of contiguous messageable types + template + requires(ContiguousMessageablesRange && !std::is_pointer_v) void snapshot(const Output& spec, T const& object) { auto& proxy = mRegistry.get().proxy(); - fair::mq::MessagePtr payloadMessage; - auto serializationType = o2::header::gSerializationMethodNone; RouteIndex routeIndex = matchDataHeader(spec, mRegistry.get().timeslice); - if constexpr (is_messageable::value == true) { - // Serialize a snapshot of a trivially copyable, non-polymorphic object, - payloadMessage = proxy.createOutputMessage(routeIndex, sizeof(T)); - memcpy(payloadMessage->GetData(), &object, sizeof(T)); - - serializationType = o2::header::gSerializationMethodNone; - } else if constexpr (is_specialization_v == true || - (gsl::details::is_span::value && has_messageable_value_type::value)) { - using ElementType = typename std::remove_pointer::type; - if constexpr (is_messageable::value) { - // Serialize a snapshot of a std::vector of trivially copyable, non-polymorphic elements - // Note: in most cases it is better to use the `make` function und work with the provided - // reference object - constexpr auto elementSizeInBytes = sizeof(ElementType); - auto sizeInBytes = elementSizeInBytes * object.size(); - payloadMessage = proxy.createOutputMessage(routeIndex, sizeInBytes); - - if constexpr (std::is_pointer::value == false) { - // vector of elements - if (object.data() && sizeInBytes) { - memcpy(payloadMessage->GetData(), object.data(), sizeInBytes); - } - } else { - // serialize vector of pointers to elements - auto target = reinterpret_cast(payloadMessage->GetData()); - for (auto const& pointer : object) { - memcpy(target, pointer, elementSizeInBytes); - target += elementSizeInBytes; - } - } - - serializationType = o2::header::gSerializationMethodNone; - } else if constexpr (has_root_dictionary::value) { - return snapshot(spec, ROOTSerialized(object)); - } else { - static_assert(always_static_assert_v, - "value type of std::vector not supported by API, supported types:" - "\n - messageable tyeps (trivially copyable, non-polymorphic structures)" - "\n - pointers to those" - "\n - types with ROOT dictionary and implementing ROOT ClassDef interface"); - } - } else if constexpr (is_container::value == true && has_messageable_value_type::value == true) { - // Serialize a snapshot of a std::container of trivially copyable, non-polymorphic elements - // Note: in most cases it is better to use the `make` function und work with the provided - // reference object - constexpr auto elementSizeInBytes = sizeof(typename T::value_type); - auto sizeInBytes = elementSizeInBytes * object.size(); - payloadMessage = proxy.createOutputMessage(routeIndex, sizeInBytes); - - // serialize vector of pointers to elements - auto target = reinterpret_cast(payloadMessage->GetData()); - for (auto const& entry : object) { - memcpy(target, (void*)&entry, elementSizeInBytes); - target += elementSizeInBytes; - } - serializationType = o2::header::gSerializationMethodNone; - } else if constexpr (has_root_dictionary::value == true || is_specialization_v == true) { - // Serialize a snapshot of an object with root dictionary - payloadMessage = proxy.createOutputMessage(routeIndex); - payloadMessage->Rebuild(4096, {64}); - if constexpr (is_specialization_v == true) { - // Explicitely ROOT serialize a snapshot of object. - // An object wrapped into type `ROOTSerialized` is explicitely marked to be ROOT serialized - // and is expected to have a ROOT dictionary. Availability can not be checked at compile time - // for all cases. - using WrappedType = typename T::wrapped_type; - static_assert(std::is_same::value || - std::is_same::value || - std::is_void::value, - "class hint must be of type TClass or const char"); - - const TClass* cl = nullptr; - if (object.getHint() == nullptr) { - // get TClass info by wrapped type - cl = TClass::GetClass(typeid(WrappedType)); - } else if (std::is_same::value) { - // the class info has been passed directly - cl = reinterpret_cast(object.getHint()); - } else if (std::is_same::value) { - // get TClass info by optional name - cl = TClass::GetClass(reinterpret_cast(object.getHint())); - } - if (has_root_dictionary::value == false && cl == nullptr) { - if (std::is_same::value) { - throw runtime_error_f("ROOT serialization not supported, dictionary not found for type %s", - reinterpret_cast(object.getHint())); - } else { - throw runtime_error_f("ROOT serialization not supported, dictionary not found for type %s", - typeid(WrappedType).name()); - } - } - typename root_serializer::serializer().Serialize(*payloadMessage, &object(), cl); + using ElementType = typename std::remove_pointer::type; + // Serialize a snapshot of a std::vector of trivially copyable, non-polymorphic elements + // Note: in most cases it is better to use the `make` function und work with the provided + // reference object + constexpr auto elementSizeInBytes = sizeof(ElementType); + auto sizeInBytes = elementSizeInBytes * object.size(); + fair::mq::MessagePtr payloadMessage = proxy.createOutputMessage(routeIndex, sizeInBytes); + + // vector of elements + if (object.data() && sizeInBytes) { + memcpy(payloadMessage->GetData(), object.data(), sizeInBytes); + } + + addPartToContext(routeIndex, std::move(payloadMessage), spec, o2::header::gSerializationMethodNone); + } + + // A random access range of pointers we can serialise by storing the contens one after the other. + // On the receiving side you will have to retrieve it via a span + template + requires(std::ranges::random_access_range && is_messageable>::value && std::is_pointer_v) + void snapshot(const Output& spec, T const& object) + { + auto& proxy = mRegistry.get().proxy(); + RouteIndex routeIndex = matchDataHeader(spec, mRegistry.get().timeslice); + using ElementType = typename std::remove_pointer_t; + // Serialize a snapshot of a std::vector of trivially copyable, non-polymorphic elements + // Note: in most cases it is better to use the `make` function und work with the provided + // reference object + constexpr auto elementSizeInBytes = sizeof(ElementType); + auto sizeInBytes = elementSizeInBytes * object.size(); + fair::mq::MessagePtr payloadMessage = proxy.createOutputMessage(routeIndex, sizeInBytes); + + // serialize vector of pointers to elements + auto target = reinterpret_cast(payloadMessage->GetData()); + for (auto const& pointer : object) { + memcpy(target, pointer, elementSizeInBytes); + target += elementSizeInBytes; + } + + addPartToContext(routeIndex, std::move(payloadMessage), spec, o2::header::gSerializationMethodNone); + } + + // This is for a range where we can know upfront how many elements there are, + // so that we can preallocate the final size by simply multipling sizeof(T) x N elements + template + requires(!std::ranges::contiguous_range && std::ranges::sized_range && has_messageable_value_type::value) + void snapshot(const Output& spec, T const& object) + { + auto& proxy = mRegistry.get().proxy(); + RouteIndex routeIndex = matchDataHeader(spec, mRegistry.get().timeslice); + // Serialize a snapshot of a std::container of trivially copyable, non-polymorphic elements + // Note: in most cases it is better to use the `make` function und work with the provided + // reference object + constexpr auto elementSizeInBytes = sizeof(typename T::value_type); + auto sizeInBytes = elementSizeInBytes * object.size(); + fair::mq::MessagePtr payloadMessage = proxy.createOutputMessage(routeIndex, sizeInBytes); + + // serialize vector of pointers to elements + auto target = reinterpret_cast(payloadMessage->GetData()); + for (auto const& entry : object) { + memcpy(target, (void*)&entry, elementSizeInBytes); + target += elementSizeInBytes; + } + addPartToContext(routeIndex, std::move(payloadMessage), spec, o2::header::gSerializationMethodNone); + } + + template + requires(is_specialization_v) + void snapshot(const Output& spec, T const& object) + { + auto& proxy = mRegistry.get().proxy(); + RouteIndex routeIndex = matchDataHeader(spec, mRegistry.get().timeslice); + // Serialize a snapshot of an object with root dictionary + fair::mq::MessagePtr payloadMessage = proxy.createOutputMessage(routeIndex); + payloadMessage->Rebuild(4096, {64}); + const TClass* cl = nullptr; + // Explicitely ROOT serialize a snapshot of object. + // An object wrapped into type `ROOTSerialized` is explicitely marked to be ROOT serialized + // and is expected to have a ROOT dictionary. Availability can not be checked at compile time + // for all cases. + using WrappedType = typename T::wrapped_type; + + if (object.getHint() == nullptr) { + // get TClass info by wrapped type + cl = TClass::GetClass(typeid(WrappedType)); + } else if (std::is_same::value) { + // the class info has been passed directly + cl = reinterpret_cast(object.getHint()); + } else if (std::is_same::value) { + // get TClass info by optional name + cl = TClass::GetClass(reinterpret_cast(object.getHint())); + } + if (has_root_dictionary::value == false && cl == nullptr) { + if (std::is_same::value) { + throw runtime_error_f("ROOT serialization not supported, dictionary not found for type %s", + reinterpret_cast(object.getHint())); } else { - typename root_serializer::serializer().Serialize(*payloadMessage, &object, TClass::GetClass(typeid(T))); + throw runtime_error_f("ROOT serialization not supported, dictionary not found for type %s", + typeid(WrappedType).name()); } - serializationType = o2::header::gSerializationMethodROOT; - } else { - static_assert(always_static_assert_v, - "data type T not supported by API, \n specializations available for" - "\n - trivially copyable, non-polymorphic structures" - "\n - std::vector of messageable structures or pointers to those" - "\n - types with ROOT dictionary and implementing ROOT ClassDef interface"); } - addPartToContext(routeIndex, std::move(payloadMessage), spec, serializationType); + typename root_serializer::serializer().Serialize(*payloadMessage, &object(), cl); + addPartToContext(routeIndex, std::move(payloadMessage), spec, o2::header::gSerializationMethodROOT); + } + + template + requires(!is_messageable::value && !ContiguousMessageablesRange && has_root_dictionary::value && !is_specialization_v) + void snapshot(const Output& spec, T const& object) + { + auto& proxy = mRegistry.get().proxy(); + RouteIndex routeIndex = matchDataHeader(spec, mRegistry.get().timeslice); + // Serialize a snapshot of an object with root dictionary + fair::mq::MessagePtr payloadMessage = proxy.createOutputMessage(routeIndex); + payloadMessage->Rebuild(4096, {64}); + typename root_serializer::serializer().Serialize(*payloadMessage, &object, TClass::GetClass(typeid(T))); + addPartToContext(routeIndex, std::move(payloadMessage), spec, o2::header::gSerializationMethodROOT); } /// Take a snapshot of a raw data array which can be either POD or may contain a serialized diff --git a/Framework/Core/include/Framework/SerializationMethods.h b/Framework/Core/include/Framework/SerializationMethods.h index 31b9d24013ab4..68c509d36905f 100644 --- a/Framework/Core/include/Framework/SerializationMethods.h +++ b/Framework/Core/include/Framework/SerializationMethods.h @@ -15,6 +15,7 @@ /// @brief Type wrappers for enfording a specific serialization method #include "Framework/TypeTraits.h" +#include namespace o2::framework { @@ -43,6 +44,9 @@ namespace o2::framework /// - or - /// ROOTSerialized(object, "classname")); template + requires(!std::is_pointer_v && (std::same_as || + std::same_as || + std::is_void_v)) class ROOTSerialized { public: @@ -50,9 +54,6 @@ class ROOTSerialized using wrapped_type = T; using hint_type = HintType; - static_assert(std::is_pointer::value == false, "wrapped type can not be a pointer"); - static_assert(std::is_pointer::value == false, "hint type can not be a pointer"); - ROOTSerialized() = delete; ROOTSerialized(wrapped_type& ref, hint_type* hint = nullptr) : mRef(ref), mHint(hint) {} @@ -67,6 +68,9 @@ class ROOTSerialized }; template + requires(!std::is_pointer_v && (std::same_as || + std::same_as || + std::is_void_v)) class CCDBSerialized { public: @@ -74,9 +78,6 @@ class CCDBSerialized using wrapped_type = T; using hint_type = HintType; - static_assert(std::is_pointer::value == false, "wrapped type can not be a pointer"); - static_assert(std::is_pointer::value == false, "hint type can not be a pointer"); - CCDBSerialized() = delete; CCDBSerialized(wrapped_type& ref, hint_type* hint = nullptr) : mRef(ref), mHint(hint) {} From c6b7d8bf9c997a631449da7a98ad7e37d67bc151 Mon Sep 17 00:00:00 2001 From: atriolo Date: Mon, 19 Jan 2026 16:33:45 +0100 Subject: [PATCH 116/234] ALICE3-TRK: added possibility to use a local response file during digitization --- .../ALICE3/TRK/base/include/TRKBase/Specs.h | 8 ++++++ .../include/TRKSimulation/Digitizer.h | 5 ++++ .../ALICE3/TRK/simulation/src/DigiParams.cxx | 3 +++ .../ALICE3/TRK/simulation/src/Digitizer.cxx | 25 +++++++++++++----- .../src/TRKDigitizerSpec.cxx | 26 +++++++++++++++++-- 5 files changed, 59 insertions(+), 8 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h index a5a60422f77eb..95f9f9b00d7f3 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h @@ -131,6 +131,14 @@ constexpr double responseYShift{15.5 * mu}; constexpr double thickness{45 * mu}; } // namespace apts +namespace alice3resp /// parameters for the alice3 chip response +{ +constexpr double pitchX{10.0 * mu}; +constexpr double pitchZ{10.0 * mu}; +constexpr double responseYShift{5 * mu}; /// center of the epitaxial layer +constexpr double thickness{20 * mu}; +} // namespace alice3resp + } // namespace o2::trk::constants #endif diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Digitizer.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Digitizer.h index 221d7b342bf59..362de63fb8cb6 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Digitizer.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Digitizer.h @@ -45,6 +45,7 @@ class Digitizer void setDigits(std::vector* dig) { mDigits = dig; } void setMCLabels(o2::dataformats::MCTruthContainer* mclb) { mMCLabels = mclb; } void setROFRecords(std::vector* rec) { mROFRecords = rec; } + void setResponseName(const std::string& name) { mRespName = name; } o2::trk::DigiParams& getParams() { return (o2::trk::DigiParams&)mParams; } const o2::trk::DigiParams& getParams() const { return mParams; } @@ -136,6 +137,8 @@ class Digitizer uint32_t mROFrameMax = 0; ///< highest RO frame of current digits uint32_t mNewROFrame = 0; ///< ROFrame corresponding to provided time + bool mIsBeforeFirstRO = false; + uint32_t mEventROFrameMin = 0xffffffff; ///< lowest RO frame for processed events (w/o automatic noise ROFs) uint32_t mEventROFrameMax = 0; ///< highest RO frame forfor processed events (w/o automatic noise ROFs) @@ -145,6 +148,8 @@ class Digitizer const o2::trk::ChipSimResponse* mChipSimRespVD = nullptr; // simulated response for VD chips const o2::trk::ChipSimResponse* mChipSimRespMLOT = nullptr; // simulated response for ML/OT chips + std::string mRespName; /// APTS or ALICE3, depending on the response to be used + bool mSimRespOrientation{false}; // wether the orientation in the response function is flipped float mSimRespVDShift{0.f}; // adjusting the Y-shift in the APTS response function to match sensor local coord. float mSimRespVDScaleX{1.f}; // scale x-local coordinate to response function x-coordinate diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx index ca4685d53de2a..e2a78702204e5 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/DigiParams.cxx @@ -74,6 +74,9 @@ void DigiParams::print() const void DigiParams::setAlpSimResponse(const o2::itsmft::AlpideSimResponse* resp) { + LOG(debug) << "Response function data path: " << resp->getDataPath(); + LOG(debug) << "Response function info: "; + // resp->print(); if (!resp) { LOGP(fatal, "cannot set response function from null"); } diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx index 7c988faebf2df..0fd8c7820ce28 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Digitizer.cxx @@ -49,7 +49,7 @@ void Digitizer::init() } } - // setting the correct response function (for the moment, for both VD and MLOT the APTS response function is udes) + // setting the correct response function (for the moment, for both VD and MLOT the same response function is used) mChipSimResp = mParams.getAlpSimResponse(); mChipSimRespVD = mChipSimResp; /// for the moment considering the same response mChipSimRespMLOT = mChipSimResp; /// for the moment considering the same response @@ -65,11 +65,24 @@ void Digitizer::init() float thicknessVD = 0.0095; // cm --- hardcoded based on geometry currently present float thicknessMLOT = o2::trk::SegmentationChip::SiliconThicknessMLOT; // 0.01 cm = 100 um --- based on geometry currently present - mSimRespVDScaleX = o2::trk::constants::apts::pitchX / o2::trk::SegmentationChip::PitchRowVD; - mSimRespVDScaleZ = o2::trk::constants::apts::pitchZ / o2::trk::SegmentationChip::PitchColVD; - mSimRespVDShift = mChipSimRespVD->getDepthMax(); // the curved, rescaled, sensors have a width from 0 to -45. Must add 10 um (= max depth) to match the APTS response. - mSimRespMLOTScaleX = o2::trk::constants::apts::pitchX / o2::trk::SegmentationChip::PitchRowMLOT; - mSimRespMLOTScaleZ = o2::trk::constants::apts::pitchZ / o2::trk::SegmentationChip::PitchColMLOT; + LOG(info) << "Using response name: " << mRespName; + + if (mRespName == "APTS") { // default + mSimRespVDScaleX = o2::trk::constants::apts::pitchX / o2::trk::SegmentationChip::PitchRowVD; + mSimRespVDScaleZ = o2::trk::constants::apts::pitchZ / o2::trk::SegmentationChip::PitchColVD; + mSimRespVDShift = mChipSimRespVD->getDepthMax(); // the curved, rescaled, sensors have a width from 0 to -45. Must add ~10 um (= max depth) to match the APTS response. + mSimRespMLOTScaleX = o2::trk::constants::apts::pitchX / o2::trk::SegmentationChip::PitchRowMLOT; + mSimRespMLOTScaleZ = o2::trk::constants::apts::pitchZ / o2::trk::SegmentationChip::PitchColMLOT; + } else if (mRespName == "ALICE3") { + mSimRespVDScaleX = o2::trk::constants::alice3resp::pitchX / o2::trk::SegmentationChip::PitchRowVD; + mSimRespVDScaleZ = o2::trk::constants::alice3resp::pitchZ / o2::trk::SegmentationChip::PitchColVD; + mSimRespVDShift = mChipSimRespVD->getDepthMax(); // the curved, rescaled, sensors have a width from 0 to -95 um. Must align the start of epi layer with the response function. + mSimRespMLOTScaleX = o2::trk::constants::alice3resp::pitchX / o2::trk::SegmentationChip::PitchRowMLOT; + mSimRespMLOTScaleZ = o2::trk::constants::alice3resp::pitchZ / o2::trk::SegmentationChip::PitchColMLOT; + } else { + LOG(fatal) << "Unknown response name: " << mRespName; + } + mSimRespMLOTShift = mChipSimRespMLOT->getDepthMax() - thicknessMLOT / 2.f; // the shift should be done considering the rescaling done to adapt to the wrong silicon thickness. TODO: remove the scaling factor for the depth when the silicon thickness match the simulated response mSimRespOrientation = false; diff --git a/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx index a3d4d1f245fc5..30f9d33983712 100644 --- a/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/TRKDigitizerSpec.cxx @@ -34,6 +34,7 @@ #include #include +#include #include using namespace o2::framework; @@ -68,6 +69,7 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer void initDigitizerTask(framework::InitContext& ic) override { mDisableQED = ic.options().get("disable-qed"); + mLocalRespFile = ic.options().get("local-response-file"); } void run(framework::ProcessingContext& pc) @@ -200,6 +202,15 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer mFinished = true; } + void setLocalResponseFunction() + { + std::unique_ptr file(TFile::Open(mLocalRespFile.data(), "READ")); + if (!file) { + LOG(fatal) << "Cannot open response file " << mLocalRespFile; + } + mDigitizer.getParams().setAlpSimResponse((const o2::itsmft::AlpideSimResponse*)file->Get("response1")); + } + void updateTimeDependentParams(ProcessingContext& pc) { static bool initOnce{false}; @@ -267,7 +278,15 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer // } if (matcher == ConcreteDataMatcher(mOrigin, "APTSRESP", 0)) { LOG(info) << mID.getName() << " loaded APTSResponseData"; - mDigitizer.getParams().setAlpSimResponse((const o2::itsmft::AlpideSimResponse*)obj); + if (mLocalRespFile.empty()) { + LOG(info) << "Using CCDB/APTS response file"; + mDigitizer.getParams().setAlpSimResponse((const o2::itsmft::AlpideSimResponse*)obj); + mDigitizer.setResponseName("APTS"); + } else { + LOG(info) << "Response function will be loaded from local file: " << mLocalRespFile; + setLocalResponseFunction(); + mDigitizer.setResponseName("ALICE3"); + } } } @@ -275,6 +294,7 @@ class TRKDPLDigitizerTask : BaseDPLDigitizer bool mWithMCTruth{true}; bool mFinished{false}; bool mDisableQED{false}; + std::string mLocalRespFile{""}; const o2::detectors::DetID mID{o2::detectors::DetID::TRK}; const o2::header::DataOrigin mOrigin{o2::header::gDataOriginTRK}; o2::trk::Digitizer mDigitizer{}; @@ -307,7 +327,9 @@ DataProcessorSpec getTRKDigitizerSpec(int channel, bool mctruth) return DataProcessorSpec{detStr + "Digitizer", inputs, makeOutChannels(detOrig, mctruth), AlgorithmSpec{adaptFromTask(mctruth)}, - Options{{"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}}}}; + Options{ + {"disable-qed", o2::framework::VariantType::Bool, false, {"disable QED handling"}}, + {"local-response-file", o2::framework::VariantType::String, "", {"use response file saved locally at this path/filename"}}}}; } } // namespace o2::trk From a09a567d02caea8d4d10219dd82243f72144c4a5 Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Tue, 27 Jan 2026 14:50:19 +0100 Subject: [PATCH 117/234] DPL Analysis: Use dangling edges context in more places (#14988) --- .../AnalysisSupport/src/AODWriterHelpers.cxx | 21 +++-- .../CCDBSupport/src/AnalysisCCDBHelpers.cxx | 58 +++++++------- .../CCDBSupport/src/AnalysisCCDBHelpers.h | 2 +- .../Core/include/Framework/AnalysisTask.h | 4 +- Framework/Core/src/AnalysisSupportHelpers.cxx | 4 +- Framework/Core/src/ArrowSupport.cxx | 27 +------ Framework/Core/src/WorkflowHelpers.cxx | 79 +++++++++---------- Framework/Core/src/WorkflowHelpers.h | 3 + 8 files changed, 87 insertions(+), 111 deletions(-) diff --git a/Framework/AnalysisSupport/src/AODWriterHelpers.cxx b/Framework/AnalysisSupport/src/AODWriterHelpers.cxx index d868b7498fb76..b76ffca13977e 100644 --- a/Framework/AnalysisSupport/src/AODWriterHelpers.cxx +++ b/Framework/AnalysisSupport/src/AODWriterHelpers.cxx @@ -62,13 +62,13 @@ const static std::unordered_map ROOTfileNa AlgorithmSpec AODWriterHelpers::getOutputTTreeWriter(ConfigContext const& ctx) { - auto& ac = ctx.services().get(); auto dod = AnalysisSupportHelpers::getDataOutputDirector(ctx); int compressionLevel = 505; if (ctx.options().hasOption("aod-writer-compression")) { compressionLevel = ctx.options().get("aod-writer-compression"); } - return AlgorithmSpec{[dod, outputInputs = ac.outputsInputsAOD, compressionLevel](InitContext& ic) -> std::function { + return AlgorithmSpec{[dod, compressionLevel](InitContext& ic) -> std::function { + auto outputInputs = ic.services().get().outputsInputsAOD; LOGP(debug, "======== getGlobalAODSink::Init =========="); // find out if any table needs to be saved @@ -241,14 +241,13 @@ AlgorithmSpec AODWriterHelpers::getOutputTTreeWriter(ConfigContext const& ctx) }; } -AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& ctx) +AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& /*ctx*/) { - using namespace monitoring; - auto& ac = ctx.services().get(); - auto tskmap = ac.outTskMap; - auto objmap = ac.outObjHistMap; - - return AlgorithmSpec{[objmap, tskmap](InitContext& ic) -> std::function { + return AlgorithmSpec{[](InitContext& ic) -> std::function { + using namespace monitoring; + auto& dec = ic.services().get(); + auto tskmap = dec.outTskMap; + auto objmap = dec.outObjHistMap; auto& callbacks = ic.services().get(); auto inputObjects = std::make_shared>>(); @@ -278,7 +277,7 @@ AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& ctx) callbacks.set(endofdatacb); return [inputObjects, objmap, tskmap](ProcessingContext& pc) mutable -> void { - auto mergePart = [&inputObjects, &objmap, &tskmap, &pc](DataRef const& ref) { + auto mergePart = [&inputObjects, &objmap, &tskmap](DataRef const& ref) { O2_SIGNPOST_ID_GENERATE(hid, histogram_registry); O2_SIGNPOST_START(histogram_registry, hid, "mergePart", "Merging histogram"); if (!ref.header) { @@ -474,7 +473,7 @@ AlgorithmSpec AODWriterHelpers::getOutputObjHistWriter(ConfigContext const& ctx) }; O2_SIGNPOST_ID_GENERATE(rid, histogram_registry); O2_SIGNPOST_START(histogram_registry, rid, "processParts", "Start merging %zu parts received together.", pc.inputs().getNofParts(0)); - for (int pi = 0; pi < pc.inputs().getNofParts(0); ++pi) { + for (auto pi = 0U; pi < pc.inputs().getNofParts(0); ++pi) { mergePart(pc.inputs().get("x", pi)); } O2_SIGNPOST_END(histogram_registry, rid, "processParts", "Done histograms in multipart message."); diff --git a/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx b/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx index 9ec911518f754..ea13d412cd0b8 100644 --- a/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx +++ b/Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx @@ -67,38 +67,38 @@ void fillValidRoutes(CCDBFetcherHelper& helper, std::vector(); - std::vector> schemas; - auto schemaMetadata = std::make_shared(); + return adaptStateful([](ConfigParamRegistry const& options, DeviceSpec const& spec, InitContext& ic) { + auto& dec = ic.services().get(); + std::vector> schemas; + auto schemaMetadata = std::make_shared(); - for (auto& input : ac.analysisCCDBInputs) { - std::vector> fields; - schemaMetadata->Append("outputRoute", DataSpecUtils::describe(input)); - schemaMetadata->Append("outputBinding", input.binding); + for (auto& input : dec.analysisCCDBInputs) { + std::vector> fields; + schemaMetadata->Append("outputRoute", DataSpecUtils::describe(input)); + schemaMetadata->Append("outputBinding", input.binding); - for (auto& m : input.metadata) { - // Save the list of input tables - if (m.name.starts_with("input:")) { - auto name = m.name.substr(6); - schemaMetadata->Append("sourceTable", name); - schemaMetadata->Append("sourceMatcher", DataSpecUtils::describe(std::get(DataSpecUtils::fromMetadataString(m.defaultValue.get()).matcher))); - continue; - } - // Ignore the non ccdb: entries - if (!m.name.starts_with("ccdb:")) { - continue; + for (auto& m : input.metadata) { + // Save the list of input tables + if (m.name.starts_with("input:")) { + auto name = m.name.substr(6); + schemaMetadata->Append("sourceTable", name); + continue; + } + // Ignore the non ccdb: entries + if (!m.name.starts_with("ccdb:")) { + continue; + } + // Create the schema of the output + auto metadata = std::make_shared(); + metadata->Append("url", m.defaultValue.asString()); + auto columnName = m.name.substr(strlen("ccdb:")); + fields.emplace_back(std::make_shared(columnName, arrow::binary_view(), false, metadata)); } - // Create the schema of the output - auto metadata = std::make_shared(); - metadata->Append("url", m.defaultValue.asString()); - auto columnName = m.name.substr(strlen("ccdb:")); - fields.emplace_back(std::make_shared(columnName, arrow::binary_view(), false, metadata)); + schemas.emplace_back(std::make_shared(fields, schemaMetadata)); } - schemas.emplace_back(std::make_shared(fields, schemaMetadata)); - } - return adaptStateful([schemas](CallbackService& callbacks, ConfigParamRegistry const& options, DeviceSpec const& spec) { + std::shared_ptr helper = std::make_shared(); CCDBFetcherHelper::initialiseHelper(*helper, options); std::unordered_map bindings; @@ -129,11 +129,11 @@ AlgorithmSpec AnalysisCCDBHelpers::fetchFromCCDB(ConfigContext const& ctx) int outputRouteIndex = bindings.at(outRouteDesc); auto& spec = helper->routes[outputRouteIndex].matcher; std::vector> builders; - for (auto& _ : schema->fields()) { + for (auto const& _ : schema->fields()) { builders.emplace_back(std::make_shared()); } - for (size_t ci = 0; ci < timestampColumn->num_chunks(); ++ci) { + for (auto ci = 0; ci < timestampColumn->num_chunks(); ++ci) { std::shared_ptr chunk = timestampColumn->chunk(ci); auto const* timestamps = chunk->data()->GetValuesSafe(1); diff --git a/Framework/CCDBSupport/src/AnalysisCCDBHelpers.h b/Framework/CCDBSupport/src/AnalysisCCDBHelpers.h index f8175034da0ba..3be2138bd2b5c 100644 --- a/Framework/CCDBSupport/src/AnalysisCCDBHelpers.h +++ b/Framework/CCDBSupport/src/AnalysisCCDBHelpers.h @@ -17,7 +17,7 @@ namespace o2::framework { struct AnalysisCCDBHelpers { - static AlgorithmSpec fetchFromCCDB(ConfigContext const& ctx); + static AlgorithmSpec fetchFromCCDB(ConfigContext const&); }; } // namespace o2::framework diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index c50b5358990de..4f8a9e719e4b9 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -521,7 +521,7 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) std::vector expressionInfos; /// make sure options and configurables are set before expression infos are created - homogeneous_apply_refs([&options, &hash](auto& element) { return analysis_task_parsers::appendOption(options, element); }, *task.get()); + homogeneous_apply_refs([&options](auto& element) { return analysis_task_parsers::appendOption(options, element); }, *task.get()); /// extract conditions and append them as inputs homogeneous_apply_refs([&inputs](auto& element) { return analysis_task_parsers::appendCondition(inputs, element); }, *task.get()); @@ -620,7 +620,7 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) } // reset pre-slice for the next dataframe auto slices = pc.services().get(); - homogeneous_apply_refs([&pc, &slices](auto& element) { + homogeneous_apply_refs([&slices](auto& element) { return analysis_task_parsers::updateSliceInfo(element, slices); }, *(task.get())); diff --git a/Framework/Core/src/AnalysisSupportHelpers.cxx b/Framework/Core/src/AnalysisSupportHelpers.cxx index 15b56f9afbff5..7453751315626 100644 --- a/Framework/Core/src/AnalysisSupportHelpers.cxx +++ b/Framework/Core/src/AnalysisSupportHelpers.cxx @@ -98,7 +98,7 @@ std::shared_ptr AnalysisSupportHelpers::getDataOutputDirecto if (!keepString.empty()) { dod->reset(); std::string d("dangling"); - if (d.find(keepString) == 0) { + if (keepString.starts_with(d)) { // use the dangling outputs std::vector danglingOutputs; for (auto ii = 0u; ii < OutputsInputs.size(); ii++) { @@ -144,7 +144,7 @@ void AnalysisSupportHelpers::addMissingOutputsToSpawner(std::vector sinks::append_to{publisher.outputs}; // append them to the publisher outputs std::vector additionalInputs; - for (auto& input : requestedSpecials | views::filter_not_matching(providedSpecials)) { + for (auto const& input : requestedSpecials | views::filter_not_matching(providedSpecials)) { input.metadata | views::filter_string_params_with("input:") | views::params_to_input_specs() | diff --git a/Framework/Core/src/ArrowSupport.cxx b/Framework/Core/src/ArrowSupport.cxx index 60277dfc38a74..31cddc9803d69 100644 --- a/Framework/Core/src/ArrowSupport.cxx +++ b/Framework/Core/src/ArrowSupport.cxx @@ -685,33 +685,8 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() } } - // replace writer as some outputs may have become dangling and some are now consumed - auto [outputsInputs, isDangling] = WorkflowHelpers::analyzeOutputs(workflow); - - // create DataOutputDescriptor - std::shared_ptr dod = AnalysisSupportHelpers::getDataOutputDirector(ctx); - - // select outputs of type AOD which need to be saved - // ATTENTION: if there are dangling outputs the getGlobalAODSink - // has to be created in any case! - dec.outputsInputsAOD.clear(); - - for (auto ii = 0u; ii < outputsInputs.size(); ii++) { - if (DataSpecUtils::partialMatch(outputsInputs[ii], extendedAODOrigins)) { - auto ds = dod->getDataOutputDescriptors(outputsInputs[ii]); - if (!ds.empty() || isDangling[ii]) { - dec.outputsInputsAOD.emplace_back(outputsInputs[ii]); - } - } - } + WorkflowHelpers::injectAODWriter(workflow, ctx); - // file sink for any AOD output - if (!dec.outputsInputsAOD.empty()) { - // add TFNumber and TFFilename as input to the writer - dec.outputsInputsAOD.emplace_back("tfn", "TFN", "TFNumber"); - dec.outputsInputsAOD.emplace_back("tff", "TFF", "TFFilename"); - workflow.push_back(AnalysisSupportHelpers::getGlobalAODSink(ctx)); - } // Move the dummy sink at the end, if needed for (size_t i = 0; i < workflow.size(); ++i) { if (workflow[i].name == "internal-dpl-injected-dummy-sink") { diff --git a/Framework/Core/src/WorkflowHelpers.cxx b/Framework/Core/src/WorkflowHelpers.cxx index ff1ff1f4cf13d..714706952d26c 100644 --- a/Framework/Core/src/WorkflowHelpers.cxx +++ b/Framework/Core/src/WorkflowHelpers.cxx @@ -420,10 +420,10 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext // AODs are being injected on-the-fly, add error-handler reader aodReader.algorithm = AlgorithmSpec{ adaptStateful( - [outputs = aodReader.outputs](DeviceSpec const&) { + [](DeviceSpec const& spec) { LOGP(warn, "Workflow with injected AODs has unsatisfied inputs:"); - for (auto const& output : outputs) { - LOGP(warn, " {}", DataSpecUtils::describe(output)); + for (auto const& output : spec.outputs) { + LOGP(warn, " {}", DataSpecUtils::describe(output.matcher)); } LOGP(fatal, "Stopping."); // to ensure the output type for adaptStateful @@ -531,43 +531,7 @@ void WorkflowHelpers::injectServiceDevices(WorkflowSpec& workflow, ConfigContext workflow.insert(workflow.end(), extraSpecs.begin(), extraSpecs.end()); extraSpecs.clear(); - /// Analyze all ouputs - auto [outputsInputsTmp, isDanglingTmp] = analyzeOutputs(workflow); - dec.isDangling = isDanglingTmp; - dec.outputsInputs = outputsInputsTmp; - - // create DataOutputDescriptor - std::shared_ptr dod = AnalysisSupportHelpers::getDataOutputDirector(ctx); - - // select outputs of type AOD which need to be saved - // ATTENTION: if there are dangling outputs the getGlobalAODSink - // has to be created in any case! - for (auto ii = 0u; ii < dec.outputsInputs.size(); ii++) { - if (DataSpecUtils::partialMatch(dec.outputsInputs[ii], extendedAODOrigins)) { - auto ds = dod->getDataOutputDescriptors(dec.outputsInputs[ii]); - if (ds.size() > 0 || dec.isDangling[ii]) { - dec.outputsInputsAOD.emplace_back(dec.outputsInputs[ii]); - } - } - } - - // file sink for any AOD output - if (dec.outputsInputsAOD.size() > 0) { - // add TFNumber and TFFilename as input to the writer - dec.outputsInputsAOD.emplace_back(InputSpec{"tfn", "TFN", "TFNumber"}); - dec.outputsInputsAOD.emplace_back(InputSpec{"tff", "TFF", "TFFilename"}); - auto fileSink = AnalysisSupportHelpers::getGlobalAODSink(ctx); - extraSpecs.push_back(fileSink); - - auto it = std::ranges::find_if(dec.outputsInputs, [](InputSpec& spec) -> bool { - return DataSpecUtils::partialMatch(spec, o2::header::DataOrigin("TFN")); - }); - size_t ii = std::distance(dec.outputsInputs.begin(), it); - dec.isDangling[ii] = false; - } - - workflow.insert(workflow.end(), extraSpecs.begin(), extraSpecs.end()); - extraSpecs.clear(); + injectAODWriter(workflow, ctx); // Select dangling outputs which are not of type AOD std::vector redirectedOutputsInputs; @@ -704,6 +668,41 @@ void WorkflowHelpers::adjustTopology(WorkflowSpec& workflow, ConfigContext const } } +void WorkflowHelpers::injectAODWriter(WorkflowSpec& workflow, ConfigContext const& ctx) +{ + auto& dec = ctx.services().get(); + /// Analyze all ouputs + std::tie(dec.outputsInputs, dec.isDangling) = analyzeOutputs(workflow); + + // create DataOutputDescriptor + std::shared_ptr dod = AnalysisSupportHelpers::getDataOutputDirector(ctx); + + // select outputs of type AOD which need to be saved + dec.outputsInputsAOD.clear(); + for (auto ii = 0u; ii < dec.outputsInputs.size(); ii++) { + if (DataSpecUtils::partialMatch(dec.outputsInputs[ii], extendedAODOrigins)) { + auto ds = dod->getDataOutputDescriptors(dec.outputsInputs[ii]); + if (ds.size() > 0 || dec.isDangling[ii]) { + dec.outputsInputsAOD.emplace_back(dec.outputsInputs[ii]); + } + } + } + + // file sink for any AOD output + if (dec.outputsInputsAOD.size() > 0) { + // add TFNumber and TFFilename as input to the writer + DataSpecUtils::updateInputList(dec.outputsInputsAOD, InputSpec{"tfn", "TFN", "TFNumber"}); + DataSpecUtils::updateInputList(dec.outputsInputsAOD, InputSpec{"tff", "TFF", "TFFilename"}); + auto fileSink = AnalysisSupportHelpers::getGlobalAODSink(ctx); + workflow.push_back(fileSink); + + auto it = std::find_if(dec.outputsInputs.begin(), dec.outputsInputs.end(), [](InputSpec const& spec) -> bool { + return DataSpecUtils::partialMatch(spec, o2::header::DataOrigin("TFN")); + }); + dec.isDangling[std::distance(dec.outputsInputs.begin(), it)] = false; + } +} + void WorkflowHelpers::constructGraph(const WorkflowSpec& workflow, std::vector& logicalEdges, std::vector& outputs, diff --git a/Framework/Core/src/WorkflowHelpers.h b/Framework/Core/src/WorkflowHelpers.h index b2a4d4cab55df..5c0aa363c6d67 100644 --- a/Framework/Core/src/WorkflowHelpers.h +++ b/Framework/Core/src/WorkflowHelpers.h @@ -182,6 +182,9 @@ struct WorkflowHelpers { // @a ctx the context for the configuration phase static void injectServiceDevices(WorkflowSpec& workflow, ConfigContext& ctx); + // Function to correctly add AOD writer + static void injectAODWriter(WorkflowSpec& workflow, ConfigContext const& ctx); + // Final adjustments to @a workflow after service devices have been injected. static void adjustTopology(WorkflowSpec& workflow, ConfigContext const& ctx); From efad2290e1efb36f28e1c84c7e062525a919eb76 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Tue, 27 Jan 2026 13:39:03 +0100 Subject: [PATCH 118/234] ITSMFT: fix number of rofs per TF Signed-off-by: Felix Schlepper --- Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx index 6809c8dee3f19..eafb72c675a58 100644 --- a/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx @@ -184,8 +184,10 @@ class ITSMFTDPLDigitizerTask : BaseDPLDigitizer // it can happen that in the digitization rofs without contributing hits are skipped // however downstream consumers of the clusters cannot know apriori the time structure // the cluster rofs do not account for the bias so it will start always at BC=0 - std::vector expDigitRofVec(nROFsTF); - for (int iROF{0}; iROF < nROFsTF; ++iROF) { + // also have to account for spillage into next TF + const size_t nROFsLayer = std::max((size_t)nROFsTF, mROFRecordsAccum[iLayer].size()); + std::vector expDigitRofVec(nROFsLayer); + for (int iROF{0}; iROF < nROFsLayer; ++iROF) { auto& rof = expDigitRofVec[iROF]; int orb = iROF * DPLAlpideParam::Instance().getROFLengthInBC(iLayer) / o2::constants::lhc::LHCMaxBunches + mFirstOrbitTF; int bc = iROF * DPLAlpideParam::Instance().getROFLengthInBC(iLayer) % o2::constants::lhc::LHCMaxBunches; @@ -204,7 +206,7 @@ class ITSMFTDPLDigitizerTask : BaseDPLDigitizer expROF.setFirstEntry(rof.getFirstEntry()); expROF.setNEntries(rof.getNEntries()); if (expROF.getBCData() != rof.getBCData()) { - LOGP(fatal, "detected mismatch between expected ROF:{} and received ROF:{}", expROF.asString(), rof.asString()); + LOGP(fatal, "detected mismatch between expected {} and received {}", expROF.asString(), rof.asString()); } } int prevFirst{0}; @@ -214,6 +216,9 @@ class ITSMFTDPLDigitizerTask : BaseDPLDigitizer } prevFirst = rof.getFirstEntry(); } + // if more rofs where accumulated than ROFs possible in the TF, cut them away + // by construction expDigitRofVec is at least nROFsTF long + expDigitRofVec.resize(nROFsTF); pc.outputs().snapshot(Output{Origin, "DIGITSROF", iLayer}, expDigitRofVec); } else { pc.outputs().snapshot(Output{Origin, "DIGITSROF", iLayer}, mROFRecordsAccum[iLayer]); From 0cf7ec22173e7817599b997d189328ba65ecabc4 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Tue, 27 Jan 2026 21:10:07 +0100 Subject: [PATCH 119/234] GPU CMake: Improve architecture auto-detection --- dependencies/FindO2GPU.cmake | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/dependencies/FindO2GPU.cmake b/dependencies/FindO2GPU.cmake index 6ca311905e01c..21e2d7cad239a 100644 --- a/dependencies/FindO2GPU.cmake +++ b/dependencies/FindO2GPU.cmake @@ -10,7 +10,12 @@ # or submit itself to any jurisdiction. # NOTE!!!! - Whenever this file is changed, move it over to alidist/resources -# FindO2GPU.cmake Version 8 +# FindO2GPU.cmake Version 9 + +set(CUDA_COMPUTETARGET_DEFAULT_FULL 80-real 86-real 89-real 120-real 75-virtual) +set(HIP_AMDGPUTARGET_DEFAULT_FULL gfx906;gfx908) +set(CUDA_COMPUTETARGET_DEFAULT_MINIMAL 75-virtual) +set(HIP_AMDGPUTARGET_DEFAULT_MINIMAL gfx906) if(NOT DEFINED ENABLE_CUDA) set(ENABLE_CUDA "AUTO") @@ -32,11 +37,11 @@ if(CMAKE_BUILD_TYPE_UPPER STREQUAL "DEBUG") endif() if(CUDA_COMPUTETARGET AND CUDA_COMPUTETARGET STREQUAL "default") - set(CUDA_COMPUTETARGET 80-real 86-real 89-real 120-real 75-virtual) + set(CUDA_COMPUTETARGET ${CUDA_COMPUTETARGET_DEFAULT_FULL}) endif() if(HIP_AMDGPUTARGET AND HIP_AMDGPUTARGET STREQUAL "default") - set(HIP_AMDGPUTARGET gfx906;gfx908) + set(HIP_AMDGPUTARGET ${HIP_AMDGPUTARGET_DEFAULT_FULL}) endif() function(set_target_cuda_arch target) @@ -112,7 +117,7 @@ if(ENABLE_CUDA) if(CUDA_COMPUTETARGET) set(CMAKE_CUDA_ARCHITECTURES ${CUDA_COMPUTETARGET}) else() - set(CMAKE_CUDA_ARCHITECTURES 75-virtual) + set(O2_GPU_CUDA_UPDATE_NATIVE_ARCHITECTURE 1) endif() set(CMAKE_CUDA_STANDARD ${CMAKE_CXX_STANDARD}) set(CMAKE_CUDA_STANDARD_REQUIRED TRUE) @@ -156,6 +161,13 @@ if(ENABLE_CUDA) set(CMAKE_CUDA_COMPILER OFF) endif() endif() + if(NOT CMAKE_CUDA_ARCHITECTURES OR O2_GPU_CUDA_UPDATE_NATIVE_ARCHITECTURE) + if(NOT CMAKE_CUDA_ARCHITECTURES_NATIVE STREQUAL "") + set(CMAKE_CUDA_ARCHITECTURES ${CMAKE_CUDA_ARCHITECTURES_NATIVE}) + else() + set(CMAKE_CUDA_ARCHITECTURES ${CUDA_COMPUTETARGET_DEFAULT_MINIMAL}) + endif() + endif() if(CMAKE_CUDA_COMPILER) set(CMAKE_CUDA_FLAGS "-Xcompiler \"${O2_GPU_CMAKE_CXX_FLAGS_NOSTD}\" ${CMAKE_CUDA_FLAGS} --expt-relaxed-constexpr --extended-lambda -Xcompiler -Wno-attributes -Wno-deprecated-gpu-targets ${GPUCA_CUDA_DENORMALS_FLAGS}") set(CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "-Xcompiler \"${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}}\" ${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE_UPPER}}") @@ -184,7 +196,7 @@ if(ENABLE_CUDA) endif() set(CUDA_ENABLED ON) - message(STATUS "CUDA found (Version ${CMAKE_CUDA_COMPILER_VERSION})") + message(STATUS "CUDA found (Version ${CMAKE_CUDA_COMPILER_VERSION}, Architectures ${CMAKE_CUDA_ARCHITECTURES})") elseif(NOT ENABLE_CUDA STREQUAL "AUTO") message(FATAL_ERROR "CUDA not found (Compiler: ${CMAKE_CUDA_COMPILER})") else() @@ -305,7 +317,6 @@ if(ENABLE_HIP) if(hip_FOUND AND hipcub_FOUND AND rocthrust_FOUND AND rocprim_FOUND AND hip_HIPCC_EXECUTABLE AND hip_HIPIFY_PERL_EXECUTABLE) set(HIP_ENABLED ON) set_target_properties(roc::rocthrust PROPERTIES IMPORTED_GLOBAL TRUE) - message(STATUS "HIP Found (${hip_HIPCC_EXECUTABLE} version ${hip_VERSION})") set(CMAKE_HIP_FLAGS "${O2_GPU_CMAKE_CXX_FLAGS_NOSTD} ${CMAKE_HIP_FLAGS} ${GPUCA_HIP_DENORMALS_FLAGS}") set(CMAKE_HIP_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} ${CMAKE_HIP_FLAGS_${CMAKE_BUILD_TYPE_UPPER}}") string(APPEND CMAKE_HIP_FLAGS " -fgpu-defer-diag -mllvm -amdgpu-enable-lower-module-lds=false -mllvm -amdgpu-function-calls=true -Wno-invalid-command-line-argument -Wno-unused-command-line-argument -Wno-invalid-constexpr -Wno-ignored-optimization-argument -Wno-unused-private-field -Wno-pass-failed ") @@ -321,6 +332,7 @@ if(ENABLE_HIP) if(HIP_AMDGPUTARGET) set(CMAKE_HIP_ARCHITECTURES "${HIP_AMDGPUTARGET}") endif() + message(STATUS "HIP Found (${hip_HIPCC_EXECUTABLE} version ${hip_VERSION}, Architectures ${CMAKE_HIP_ARCHITECTURES})") else() set(HIP_ENABLED OFF) endif() From cb66b5edfc8322bc792b255368e52a897066c76a Mon Sep 17 00:00:00 2001 From: shahor02 Date: Wed, 28 Jan 2026 09:53:51 +0100 Subject: [PATCH 120/234] Add extra info with charge and timing and occupancy to unbinned residuals (#14969) * Add extra info with charge and timing to unbinned residuals * Store TOF time wrt t0 in DetInfoRes, diff to expectation in trackData.deltaTOF * Add per-stack TPC mult info to TrackData --- .../tpcinterpolationworkflow/CMakeLists.txt | 2 + .../TPCResidualAggregatorSpec.h | 6 +- .../TPCUnbinnedResidualReaderSpec.h | 1 + .../src/TPCInterpolationSpec.cxx | 15 +- .../src/TPCResidualWriterSpec.cxx | 1 + .../src/TPCUnbinnedResidualReaderSpec.cxx | 7 + .../calibration/SpacePoints/CMakeLists.txt | 3 +- .../include/SpacePoints/ResidualAggregator.h | 3 +- .../include/SpacePoints/TrackInterpolation.h | 95 ++++++++++- .../SpacePoints/src/ResidualAggregator.cxx | 10 +- .../SpacePoints/src/SpacePointCalibLinkDef.h | 2 + .../SpacePoints/src/TrackInterpolation.cxx | 154 ++++++++++++++++-- 12 files changed, 269 insertions(+), 30 deletions(-) diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/CMakeLists.txt b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/CMakeLists.txt index c8db0209d4471..09ec6081b06b8 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/CMakeLists.txt +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/CMakeLists.txt @@ -9,6 +9,8 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +# add_compile_options(-O0 -g -fPIC -fno-omit-frame-pointer) + o2_add_library(TPCInterpolationWorkflow SOURCES src/TPCInterpolationSpec.cxx src/TPCResidualWriterSpec.cxx diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCResidualAggregatorSpec.h b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCResidualAggregatorSpec.h index b9c99f9e65676..99f20e390a09a 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCResidualAggregatorSpec.h +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCResidualAggregatorSpec.h @@ -128,8 +128,9 @@ class ResidualAggregatorDevice : public o2::framework::Task updateTimeDependentParams(pc); std::chrono::duration ccdbUpdateTime = std::chrono::high_resolution_clock::now() - runStartTime; - // we always require the unbinned residuals and the associated track references + // we always require the unbinned residuals and the associated detector info and track references auto residualsData = pc.inputs().get>("unbinnedRes"); + auto residualsDataDet = pc.inputs().get>("detinfoRes"); auto trackRefs = pc.inputs().get>("trackRefs"); // track data input is optional @@ -151,7 +152,7 @@ class ResidualAggregatorDevice : public o2::framework::Task o2::base::TFIDInfoHelper::fillTFIDInfo(pc, mAggregator->getCurrentTFInfo()); LOG(detail) << "Processing TF " << mAggregator->getCurrentTFInfo().tfCounter << " with " << trkData->size() << " tracks and " << residualsData.size() << " unbinned residuals associated to them"; - mAggregator->process(residualsData, trackRefs, trkDataPtr, lumi); + mAggregator->process(residualsData, residualsDataDet, trackRefs, trkDataPtr, lumi); std::chrono::duration runDuration = std::chrono::high_resolution_clock::now() - runStartTime; LOGP(debug, "Duration for run method: {} ms. From this taken for time dependent param update: {} ms", std::chrono::duration_cast(runDuration).count(), @@ -222,6 +223,7 @@ DataProcessorSpec getTPCResidualAggregatorSpec(bool trackInput, bool ctpInput, b auto& inputs = dataRequest->inputs; o2::tpc::VDriftHelper::requestCCDBInputs(inputs); inputs.emplace_back("unbinnedRes", "GLO", "UNBINNEDRES"); + inputs.emplace_back("detinfoRes", "GLO", "DETINFORES"); inputs.emplace_back("trackRefs", "GLO", "TRKREFS"); if (trackInput) { inputs.emplace_back("trkData", "GLO", "TRKDATA"); diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCUnbinnedResidualReaderSpec.h b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCUnbinnedResidualReaderSpec.h index 6c40bb355eb21..724151c90576f 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCUnbinnedResidualReaderSpec.h +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCUnbinnedResidualReaderSpec.h @@ -43,6 +43,7 @@ class TPCUnbinnedResidualReader : public o2::framework::Task std::string mInFileName; std::string mInTreeName; std::vector mUnbinnedResid, *mUnbinnedResidPtr = &mUnbinnedResid; + std::vector mDetInfoUnbRes, *mDetInfoUnbResPtr = &mDetInfoUnbRes; std::vector mTrackData, *mTrackDataPtr = &mTrackData; std::vector mTrackDataCompact, *mTrackDataCompactPtr = &mTrackDataCompact; }; diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx index da2fcaab913d7..4912a1df36a33 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx @@ -66,11 +66,12 @@ void TPCInterpolationDPL::updateTimeDependentParams(ProcessingContext& pc) initOnceDone = true; // other init-once stuff const auto& param = SpacePointsCalibConfParam::Instance(); + mInterpolation.setSqrtS(o2::base::GRPGeomHelper::instance().getGRPLHCIF()->getSqrtS()); + mInterpolation.setNHBPerTF(o2::base::GRPGeomHelper::getNHBFPerTF()); mInterpolation.init(mSources, mSourcesMap); if (mProcessITSTPConly) { mInterpolation.setProcessITSTPConly(); } - mInterpolation.setSqrtS(o2::base::GRPGeomHelper::instance().getGRPLHCIF()->getSqrtS()); int nTfs = mSlotLength / (o2::base::GRPGeomHelper::getNHBFPerTF() * o2::constants::lhc::LHCOrbitMUS * 1e-6); bool limitTracks = (param.maxTracksPerCalibSlot < 0) ? false : true; int nTracksPerTfMax = (nTfs > 0 && limitTracks) ? param.maxTracksPerCalibSlot / nTfs : -1; @@ -93,6 +94,11 @@ void TPCInterpolationDPL::updateTimeDependentParams(ProcessingContext& pc) mInterpolation.setProcessSeeds(); } o2::its::GeometryTGeo::Instance()->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2GRot) | o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L)); + mInterpolation.setExtDetResid(mExtDetResid); + mInterpolation.setITSClusterDictionary(mITSDict); + if (mDebugOutput) { + mInterpolation.setDumpTrackPoints(); + } } // we may have other params which need to be queried regularly if (mTPCVDriftHelper.isUpdated()) { @@ -103,11 +109,6 @@ void TPCInterpolationDPL::updateTimeDependentParams(ProcessingContext& pc) mInterpolation.setTPCVDrift(mTPCVDriftHelper.getVDriftObject()); mTPCVDriftHelper.acknowledgeUpdate(); } - if (mDebugOutput) { - mInterpolation.setDumpTrackPoints(); - } - mInterpolation.setExtDetResid(mExtDetResid); - mInterpolation.setITSClusterDictionary(mITSDict); } void TPCInterpolationDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) @@ -143,6 +144,7 @@ void TPCInterpolationDPL::run(ProcessingContext& pc) } } pc.outputs().snapshot(Output{"GLO", "UNBINNEDRES", 0}, mInterpolation.getClusterResiduals()); + pc.outputs().snapshot(Output{"GLO", "DETINFORES", 0}, mInterpolation.getClusterResidualsDetInfo()); pc.outputs().snapshot(Output{"GLO", "TRKREFS", 0}, mInterpolation.getTrackDataCompact()); if (mSendTrackData) { pc.outputs().snapshot(Output{"GLO", "TRKDATA", 0}, mInterpolation.getReferenceTracks()); @@ -188,6 +190,7 @@ DataProcessorSpec getTPCInterpolationSpec(GTrackID::mask_t srcCls, GTrackID::mas } } outputs.emplace_back("GLO", "UNBINNEDRES", 0, Lifetime::Timeframe); + outputs.emplace_back("GLO", "DETINFORES", 0, Lifetime::Timeframe); outputs.emplace_back("GLO", "TRKREFS", 0, Lifetime::Timeframe); if (sendTrackData) { outputs.emplace_back("GLO", "TRKDATA", 0, Lifetime::Timeframe); diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCResidualWriterSpec.cxx b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCResidualWriterSpec.cxx index 5f6d7ad7b361c..8b06444bdb9b3 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCResidualWriterSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCResidualWriterSpec.cxx @@ -38,6 +38,7 @@ DataProcessorSpec getTPCResidualWriterSpec(bool writeTrackData, bool debugOutput BranchDefinition>{InputSpec{"tracksUnfiltered", "GLO", "TPCINT_TRK", 0}, "tracksUnfiltered", ((writeUnfiltered && writeTrackData) ? 1 : 0)}, BranchDefinition>{InputSpec{"residualsUnfiltered", "GLO", "TPCINT_RES", 0}, "residualsUnfiltered", (writeUnfiltered ? 1 : 0)}, BranchDefinition>{InputSpec{"residuals", "GLO", "UNBINNEDRES"}, "residuals"}, + BranchDefinition>{InputSpec{"detInfo", "GLO", "DETINFORES"}, "detInfo"}, BranchDefinition>{InputSpec{"trackRefs", "GLO", "TRKREFS"}, "trackRefs"}, BranchDefinition>{InputSpec{"tracks", "GLO", "TRKDATA"}, "tracks", (writeTrackData ? 1 : 0)}, BranchDefinition>{InputSpec{"trackExt", "GLO", "TRKDATAEXT"}, "trackExt", (debugOutput ? 1 : 0)})(); diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCUnbinnedResidualReaderSpec.cxx b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCUnbinnedResidualReaderSpec.cxx index 55da5a5e71e44..c2dae375731a4 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCUnbinnedResidualReaderSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCUnbinnedResidualReaderSpec.cxx @@ -44,6 +44,11 @@ void TPCUnbinnedResidualReader::connectTree() assert(mTreeIn); mTreeIn->SetBranchAddress("residuals", &mUnbinnedResidPtr); mTreeIn->SetBranchAddress("trackRefs", &mTrackDataCompactPtr); + if (mTreeIn->GetBranch("detInfo")) { + mTreeIn->SetBranchAddress("detInfo", &mDetInfoUnbResPtr); + } else { + LOGP(warn, "No detInfo branch found in the unbinned residuals tree, empty vector will be sent"); + } if (mTrackInput) { mTreeIn->SetBranchAddress("tracks", &mTrackDataPtr); } @@ -58,6 +63,7 @@ void TPCUnbinnedResidualReader::run(ProcessingContext& pc) LOG(info) << "Pushing " << mUnbinnedResid.size() << " unbinned residuals at entry " << currEntry; pc.outputs().snapshot(Output{"GLO", "UNBINNEDRES", 0}, mUnbinnedResid); pc.outputs().snapshot(Output{"GLO", "TRKREFS", 0}, mTrackDataCompact); + pc.outputs().snapshot(Output{"GLO", "DETINFORES", 0}, mDetInfoUnbRes); if (mTrackInput) { LOG(info) << "Pushing " << mTrackData.size() << " reference tracks for these residuals"; pc.outputs().snapshot(Output{"GLO", "TRKDATA", 0}, mTrackData); @@ -73,6 +79,7 @@ DataProcessorSpec getUnbinnedTPCResidualsReaderSpec(bool trkInput) { std::vector outputs; outputs.emplace_back("GLO", "UNBINNEDRES", 0, Lifetime::Timeframe); + outputs.emplace_back("GLO", "DETINFORES", 0, Lifetime::Timeframe); outputs.emplace_back("GLO", "TRKREFS", 0, Lifetime::Timeframe); if (trkInput) { outputs.emplace_back("GLO", "TRKDATA", 0, Lifetime::Timeframe); diff --git a/Detectors/TPC/calibration/SpacePoints/CMakeLists.txt b/Detectors/TPC/calibration/SpacePoints/CMakeLists.txt index 510cff4f7760c..47bb9c09a9951 100644 --- a/Detectors/TPC/calibration/SpacePoints/CMakeLists.txt +++ b/Detectors/TPC/calibration/SpacePoints/CMakeLists.txt @@ -29,7 +29,8 @@ o2_add_library(SpacePoints O2::DataFormatsITSMFT O2::DataFormatsTRD O2::DataFormatsTOF - O2::DataFormatsGlobalTracking) + O2::DataFormatsGlobalTracking + O2::GPUTracking) o2_target_root_dictionary(SpacePoints HEADERS include/SpacePoints/TrackResiduals.h diff --git a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/ResidualAggregator.h b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/ResidualAggregator.h index a02d830cfe45d..00af697da3a9b 100644 --- a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/ResidualAggregator.h +++ b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/ResidualAggregator.h @@ -49,7 +49,7 @@ struct ResidualsContainer { void fillStatisticsBranches(); uint64_t getNEntries() const { return nResidualsTotal; } - void fill(const o2::dataformats::TFIDInfo& ti, const gsl::span resid, const gsl::span trkRefsIn, const gsl::span* trkDataIn, const o2::ctp::LumiInfo* lumiInput); + void fill(const o2::dataformats::TFIDInfo& ti, const gsl::span resid, const gsl::span detInfoRes, const gsl::span trkRefsIn, const gsl::span* trkDataIn, const o2::ctp::LumiInfo* lumiInput); void merge(ResidualsContainer* prev); void print(); void writeToFile(bool closeFileAfterwards); @@ -64,6 +64,7 @@ struct ResidualsContainer { std::vector sumUnbinnedResid, *sumUnbinnedResidPtr{&sumUnbinnedResid}; ///< sum of unbinned residuals for each TF std::vector lumi, *lumiPtr{&lumi}; ///< luminosity information from CTP per TF std::vector unbinnedRes, *unbinnedResPtr{&unbinnedRes}; ///< unbinned residuals which are sent to the aggregator + std::vector detInfoUnbRes, *detInfoUnbResPtr{&detInfoUnbRes}; ///< detector info associated to unbinned residuals which are sent to the aggregator std::vector trkData, *trkDataPtr{&trkData}; ///< track data and cluster ranges std::vector trackInfo, *trackInfoPtr{&trackInfo}; ///< allows to obtain track type for each unbinned residual downstream o2::ctp::LumiInfo lumiTF; ///< for each processed TF we store the lumi information in the tree of unbinned residuals diff --git a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h index 992925179ffce..e7d0fb197ea42 100644 --- a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h +++ b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h @@ -47,6 +47,11 @@ class TTree; namespace o2 { +namespace gpu +{ +class GPUParam; +} + namespace tpc { class VDriftCorrFact; @@ -101,15 +106,72 @@ struct UnbinnedResid { ClassDefNV(UnbinnedResid, 2); }; +struct DetInfoResid { // detector info associated with residual + uint32_t word = 0; // container interpreted in a different way depending on the detector type + // + // TPC view: qTot and qMax of the cluster + uint16_t qTotTPC() const { return static_cast(word & 0xFFFFu); } + uint16_t qMaxTPC() const { return static_cast((word >> 16) & 0xFFFFu); } + void setTPC(uint16_t qTot, uint16_t qMax) { word = (static_cast(qMax) << 16) | static_cast(qTot); } + // + // TRD view: q0, q1, q2 + calibrated slope (truncated to in +-3.5 range) + static constexpr uint32_t TRDQ0NB = 7, TRDQ1NB = 7, TRDQ2NB = 6, TRDSlpNB = 12; + static constexpr uint32_t TRDQ0Msk = (1 << TRDQ0NB) - 1, TRDQ1Msk = (1 << TRDQ1NB) - 1, TRDQ2Msk = ((1 << TRDQ2NB) - 1), TRDSlpMsk = (1 << TRDSlpNB) - 1; + static constexpr float TRDMaxSlope = 3.5, TRDSlope2Int = ((1 << TRDSlpNB) - 1) / (2 * TRDMaxSlope), TRDInt2Slope = 1.f / TRDSlope2Int; + uint16_t q0TRD() const { return static_cast(word & TRDQ0Msk); } + uint16_t q1TRD() const { return static_cast((word >> TRDQ0NB) & TRDQ1Msk); } + uint16_t q2TRD() const { return static_cast((word >> (TRDQ0NB + TRDQ1NB)) & TRDQ2Msk); } + float slopeTRD() const { return ((word >> (TRDQ0NB + TRDQ1NB + TRDQ2NB)) & TRDSlpMsk) * TRDInt2Slope - TRDMaxSlope; } + void setTRD(uint8_t q0, uint8_t q1, uint8_t q2, float slope) + { + float rslope = (slope + TRDMaxSlope) * TRDSlope2Int; + if (rslope < 0.f) { + rslope = 0; + } else if (rslope > TRDSlpMsk) { + rslope = TRDSlpMsk; + } + uint32_t slpI = std::round(rslope); + word = (static_cast(slpI << (TRDQ0NB + TRDQ1NB + TRDQ2NB)) | + static_cast((q2 & TRDQ2Msk) << (TRDQ0NB + TRDQ1NB)) | + static_cast((q1 & TRDQ1Msk) << TRDQ0NB) | + static_cast(q0 & TRDQ0Msk)); + } + // + // TOF view (time difference in \mus wrt seeding ITS-TPC track) + float timeTOF() const { return std::bit_cast(word); } + void setTOF(float t) { word = std::bit_cast(t); } + // + // No info for ITS is stored + // + // PV view (time difference in \mus wrt contributing ITS-TPC track) + float timePV() const { return std::bit_cast(word); } + void setPV(float t) { word = std::bit_cast(t); } + + ClassDefNV(DetInfoResid, 1); +}; + /// Structure for the information required to associate each residual with a given track type (ITS-TPC-TRD-TOF, etc) struct TrackDataCompact { TrackDataCompact() = default; - TrackDataCompact(uint32_t idx, uint8_t nRes, uint8_t source, uint8_t nextraRes = 0) : idxFirstResidual(idx), nResiduals(nRes), sourceId(source), nExtDetResid(nextraRes) {} + TrackDataCompact(uint32_t idx, std::array mlt, uint8_t nRes, uint8_t source, uint8_t nextraRes = 0) : idxFirstResidual(idx), multStack{mlt}, nResiduals(nRes), sourceId(source), nExtDetResid(nextraRes) {} uint32_t idxFirstResidual; ///< the index of the first residual from this track + std::array multStack{}; // multiplicity in the stack packed as asinh(x*0.05)/0.05 uint8_t nResiduals; ///< total number of TPC residuals associated to this track uint8_t nExtDetResid = 0; ///< number of external detectors (wrt TPC) residuals stored, on top of clIdx.getEntries uint8_t sourceId; ///< source ID obtained from the global track ID - ClassDefNV(TrackDataCompact, 2); + + void setMultStack(float v, int stack) + { + uint32_t mltPacked = std::round(std::asinh(v * 0.05) / 0.05); + multStack[stack] = mltPacked < 0xff ? mltPacked : 0xff; + } + float getMultStack(int stack) const + { + return std::sinh(multStack[stack] * 0.05) / 0.05; + } + float getMultStackPacked(int stack) const { return multStack[stack]; } + + ClassDefNV(TrackDataCompact, 3); }; // TODO add to UnbinnedResid::sec flag if cluster was used or not @@ -149,11 +211,22 @@ struct TrackData { short TRDTrkltSlope[6] = {}; ///< TRD tracklet slope 0x7fff / param::MaxTRDSlope uint8_t nExtDetResid = 0; ///< number of external detectors (to TPC) residuals stored, on top of clIdx.getEntries o2::dataformats::RangeReference<> clIdx{}; ///< index of first cluster residual and total number of TPC cluster residuals of this track - + std::array multStack{}; // multiplicity in the stack packed as asinh(x*0.05)/0.05 float getT0Error() const { return float(clAvailTOF); } bool isTOFAvail() const { return clAvailTOF != 0; } - ClassDefNV(TrackData, 9); + void setMultStack(float v, int stack) + { + uint32_t mltPacked = std::round(std::asinh(v * 0.05) / 0.05); + multStack[stack] = mltPacked < 0xff ? mltPacked : 0xff; + } + float getMultStack(int stack) const + { + return std::sinh(multStack[stack] * 0.05) / 0.05; + } + float getMultStackPacked(int stack) const { return multStack[stack]; } + + ClassDefNV(TrackData, 10); }; /// \class TrackInterpolation @@ -268,6 +341,8 @@ class TrackInterpolation void diffToMA(const int np, const std::array& y, std::array& diffMA) const; // -------------------------------------- settings -------------------------------------------------- + void setNHBPerTF(int n) { mNHBPerTF = n; } + void setTPCVDrift(const o2::tpc::VDriftCorrFact& v); /// Sets the flag if material correction should be applied when extrapolating the tracks @@ -296,10 +371,13 @@ class TrackInterpolation void setExtDetResid(bool v) { mExtDetResid = v; } - int processTRDLayer(const o2::trd::TrackTRD& trkTRD, int iLayer, o2::track::TrackParCov& trkWork, std::array* trkltTRDYZ = nullptr, std::array* trkltTRDCov = nullptr, TrackData* trkData = nullptr); + int processTRDLayer(const o2::trd::TrackTRD& trkTRD, int iLayer, o2::track::TrackParCov& trkWork, std::array* trkltTRDYZ = nullptr, + std::array* trkltTRDCov = nullptr, TrackData* trkData = nullptr, + o2::trd::Tracklet64* trk64 = nullptr, o2::trd::CalibratedTracklet* trkCalib = nullptr); // --------------------------------- output --------------------------------------------- std::vector& getClusterResiduals() { return mClRes; } + std::vector& getClusterResidualsDetInfo() { return mDetInfoRes; } std::vector& getTrackDataCompact() { return mTrackDataCompact; } std::vector& getTrackDataExtended() { return mTrackDataExtended; } std::vector& getReferenceTracks() { return mTrackData; } @@ -308,8 +386,14 @@ class TrackInterpolation private: static constexpr float sFloatEps{1.e-7f}; ///< float epsilon for robust linear fitting + static constexpr int NSTACKS = 4; + static constexpr std::array STACKROWS{0, 63, 97, 127, 152}; // parameters + settings const SpacePointsCalibConfParam* mParams = nullptr; + std::shared_ptr mTPCParam = nullptr; + int mNHBPerTF = 32; + int mNTPCOccBinLength = 16; ///< TPC occupancy bin length in TB + float mNTPCOccBinLengthInv = 1.f / 16; ///< its inverse float mTPCTimeBinMUS{.2f}; ///< TPC time bin duration in us float mTPCVDriftRef = -1.; ///< TPC nominal drift speed in cm/microseconds float mTPCDriftTimeOffsetRef = 0.; ///< TPC nominal (e.g. at the start of run) drift time bias in cm/mus @@ -348,6 +432,7 @@ class TrackInterpolation std::vector mTrackDataCompact{}; ///< required to connect each residual to a global track std::vector mTrackDataExtended{}; ///< full tracking information for debugging std::vector mClRes{}; ///< residuals for each available TPC cluster of all tracks + std::vector mDetInfoRes{}; ///< packed detector info associated with each residual std::vector mTrackDataUnfiltered{}; ///< same as mTrackData, but for all tracks before outlier filtering std::vector mClResUnfiltered{}; ///< same as mClRes, but for all residuals before outlier filtering diff --git a/Detectors/TPC/calibration/SpacePoints/src/ResidualAggregator.cxx b/Detectors/TPC/calibration/SpacePoints/src/ResidualAggregator.cxx index a120c0e4ae782..b916e14dbf741 100644 --- a/Detectors/TPC/calibration/SpacePoints/src/ResidualAggregator.cxx +++ b/Detectors/TPC/calibration/SpacePoints/src/ResidualAggregator.cxx @@ -124,6 +124,7 @@ void ResidualsContainer::init(const TrackResiduals* residualsEngine, std::string treeOutResidualsUnbinned->Branch("trackInfo", &trackInfoPtr); treeOutResidualsUnbinned->Branch("CTPLumi", &lumiTF); treeOutResidualsUnbinned->Branch("timeMS", &timeMS); + treeOutResidualsUnbinned->Branch("detInfo", &detInfoUnbResPtr); } if (writeTrackData) { treeOutTrackData = std::make_unique("trackData", "Track information incl cluster range ref"); @@ -170,7 +171,7 @@ void ResidualsContainer::fillStatisticsBranches() } } -void ResidualsContainer::fill(const o2::dataformats::TFIDInfo& ti, const gsl::span resid, const gsl::span trkRefsIn, const gsl::span* trkDataIn, const o2::ctp::LumiInfo* lumiInput) +void ResidualsContainer::fill(const o2::dataformats::TFIDInfo& ti, const gsl::span resid, const gsl::span detInfoRes, const gsl::span trkRefsIn, const gsl::span* trkDataIn, const o2::ctp::LumiInfo* lumiInput) { // receives large vector of unbinned residuals and fills the sector-wise vectors // with binned residuals and statistics @@ -185,13 +186,14 @@ void ResidualsContainer::fill(const o2::dataformats::TFIDInfo& ti, const gsl::sp firstSeenTF = ti.tfCounter; } for (const auto& residIn : resid) { - ++nUnbinnedResidualsInTF; bool counterIncremented = false; if (writeUnbinnedResiduals) { unbinnedRes.push_back(residIn); + detInfoUnbRes.push_back(detInfoRes.size() ? detInfoRes[nUnbinnedResidualsInTF] : DetInfoResid{}); ++nResidualsTotal; counterIncremented = true; } + ++nUnbinnedResidualsInTF; if (!writeBinnedResid) { continue; } @@ -247,6 +249,7 @@ void ResidualsContainer::fill(const o2::dataformats::TFIDInfo& ti, const gsl::sp timeMS = orbitReset + ti.tfCounter * o2::constants::lhc::LHCOrbitMUS * 1.e-3; treeOutResidualsUnbinned->Fill(); unbinnedRes.clear(); + detInfoUnbRes.clear(); trackInfo.clear(); } tfOrbits.push_back(ti.firstTForbit); @@ -338,6 +341,9 @@ void ResidualsContainer::merge(ResidualsContainer* prev) if (writeUnbinnedResiduals) { prev->treeOutResidualsUnbinned->SetBranchAddress("res", &unbinnedResPtr); prev->treeOutResidualsUnbinned->SetBranchAddress("trackInfo", &trackInfoPtr); + prev->treeOutResidualsUnbinned->SetBranchAddress("CTPLumi", &lumiTF); + prev->treeOutResidualsUnbinned->SetBranchAddress("timeMS", &timeMS); + prev->treeOutResidualsUnbinned->SetBranchAddress("detInfo", &detInfoUnbResPtr); for (int i = 0; i < treeOutResidualsUnbinned->GetEntries(); ++i) { treeOutResidualsUnbinned->GetEntry(i); prev->treeOutResidualsUnbinned->Fill(); diff --git a/Detectors/TPC/calibration/SpacePoints/src/SpacePointCalibLinkDef.h b/Detectors/TPC/calibration/SpacePoints/src/SpacePointCalibLinkDef.h index b109a610f60b5..a3f9f3fe2267c 100644 --- a/Detectors/TPC/calibration/SpacePoints/src/SpacePointCalibLinkDef.h +++ b/Detectors/TPC/calibration/SpacePoints/src/SpacePointCalibLinkDef.h @@ -29,7 +29,9 @@ #pragma link C++ class o2::tpc::TrackResiduals::VoxRes + ; #pragma link C++ class o2::tpc::TrackResiduals::VoxStats + ; #pragma link C++ class o2::tpc::UnbinnedResid + ; +#pragma link C++ class o2::tpc::DetInfoResid + ; #pragma link C++ class std::vector < o2::tpc::UnbinnedResid> + ; +#pragma link C++ class std::vector < o2::tpc::DetInfoResid> + ; #pragma link C++ class std::vector < o2::tpc::TrackResiduals::LocalResid> + ; #pragma link C++ class std::vector < o2::tpc::TrackResiduals::VoxStats> + ; #pragma link C++ class o2::tpc::ResidualAggregator + ; diff --git a/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx b/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx index 7db5b7455f1a7..6c37be9ddc1b1 100644 --- a/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx +++ b/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx @@ -33,6 +33,11 @@ #include "DataFormatsTPC/VDriftCorrFact.h" #include "Framework/Logger.h" #include "CCDB/BasicCCDBManager.h" +#include "GPUO2InterfaceUtils.h" +#include "GPUO2InterfaceConfiguration.h" +#include "GPUO2InterfaceRefit.h" +#include "GPUParam.h" +#include "GPUParam.inc" #include #include #include @@ -135,7 +140,7 @@ void TrackInterpolation::init(o2::dataformats::GlobalTrackID::mask_t src, o2::da auto geom = o2::its::GeometryTGeo::Instance(); geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G)); - + mTPCParam = o2::gpu::GPUO2InterfaceUtils::getFullParamShared(0.f, mNHBPerTF); mInitDone = true; LOGP(info, "Done initializing TrackInterpolation. Configured track input: {}. Track input specifically for map: {}", GTrackID::getSourcesNames(mSourcesConfigured), mSingleSourcesConfigured ? "identical" : GTrackID::getSourcesNames(mSourcesConfiguredMap)); @@ -316,6 +321,10 @@ void TrackInterpolation::process() // set the input containers mTPCTracksClusIdx = mRecoCont->getTPCTracksClusterRefs(); mTPCClusterIdxStruct = &mRecoCont->getTPCClusters(); + int nbOccTOT = o2::gpu::GPUO2InterfaceRefit::fillOccupancyMapGetSize(mNHBPerTF, mTPCParam.get()); + o2::gpu::GPUO2InterfaceUtils::paramUseExternalOccupancyMap(mTPCParam.get(), mNHBPerTF, mRecoCont->occupancyMapTPC.data(), nbOccTOT); + mNTPCOccBinLength = mTPCParam->rec.tpc.occupancyMapTimeBins; + mNTPCOccBinLengthInv = 1.f / mNTPCOccBinLength; { if (!mITSDict) { LOG(error) << "No ITS dictionary available"; @@ -354,6 +363,7 @@ void TrackInterpolation::process() int maxOutputTracks = (mMaxTracksPerTF >= 0) ? mMaxTracksPerTF + mAddTracksForMapPerTF : nSeeds; mTrackData.reserve(maxOutputTracks); mClRes.reserve(maxOutputTracks * param::NPadRows); + mDetInfoRes.reserve(maxOutputTracks * param::NPadRows); bool maxTracksReached = false; for (int iSeed = 0; iSeed < nSeeds; ++iSeed) { if (mMaxTracksPerTF >= 0 && mTrackDataCompact.size() >= mMaxTracksPerTF + mAddTracksForMapPerTF) { @@ -435,6 +445,8 @@ void TrackInterpolation::interpolateTrack(int iSeed) { LOGP(debug, "Starting track interpolation for GID {}", mGIDs[iSeed].asString()); TrackData trackData; + o2::trd::Tracklet64 trkl64; + o2::trd::CalibratedTracklet trklCalib; std::unique_ptr trackDataExtended; std::vector clusterResiduals; auto propagator = o2::base::Propagator::Instance(); @@ -468,7 +480,9 @@ void TrackInterpolation::interpolateTrack(int iSeed) trackData.clIdx.setFirstEntry(mClRes.size()); // reference the first cluster residual belonging to this track float clusterTimeBinOffset = mTrackTimes[iSeed] / mTPCTimeBinMUS; - // store the TPC cluster positions in the cache + // store the TPC cluster positions in the cache, as well as dedx info + std::array, constants::MAXGLOBALPADROW> mCacheDEDX{}; + std::array multBins{}; for (int iCl = trkTPC.getNClusterReferences(); iCl--;) { uint8_t sector, row; uint32_t clusterIndexInRow; @@ -481,6 +495,12 @@ void TrackInterpolation::interpolateTrack(int iSeed) mCache[row].clY = clTPCYZ[0]; mCache[row].clZ = clTPCYZ[1]; mCache[row].clAngle = o2::math_utils::sector2Angle(sector); + mCacheDEDX[row].first = clTPC.getQtot(); + mCacheDEDX[row].second = clTPC.getQmax(); + int imb = int(clTPC.getTime() * mNTPCOccBinLengthInv); + if (imb < mTPCParam->occupancyMapSize) { + multBins[row] = 1 + std::max(0, imb); + } } // extrapolate seed through TPC and store track position at each pad row @@ -627,10 +647,19 @@ void TrackInterpolation::interpolateTrack(int iSeed) trackData.nClsTPC = trkTPC.getNClusterReferences(); trackData.nClsITS = trkITS.getNumberOfClusters(); trackData.nTrkltsTRD = gidTable[GTrackID::TRD].isIndexSet() ? mRecoCont->getITSTPCTRDTrack(gidTable[GTrackID::ITSTPCTRD]).getNtracklets() : 0; + + double t0forTOF = 0.; // to be set if TOF is matched + float t0forTOFwithinBC = 0.f; + float t0forTOFres = 9999.f; + if (gidTable[GTrackID::TOF].isIndexSet()) { const auto& tofMatch = mRecoCont->getTOFMatch(mGIDs[iSeed]); - trackData.deltaTOF = tofMatch.getSignal() - tofMatch.getFT0Best() - tofMatch.getLTIntegralOut().getTOF(trkTPC.getPID().getID()); - trackData.clAvailTOF = uint16_t(tofMatch.getFT0BestRes()); + ULong64_t bclongtof = (tofMatch.getSignal() - 10000) * o2::tof::Geo::BC_TIME_INPS_INV; + t0forTOF = tofMatch.getFT0Best(); // setting t0 for TOF + t0forTOFwithinBC = t0forTOF - bclongtof * o2::tof::Geo::BC_TIME_INPS; + t0forTOFres = tofMatch.getFT0BestRes(); + trackData.deltaTOF = tofMatch.getSignal() - t0forTOF - tofMatch.getLTIntegralOut().getTOF(trkTPC.getPID().getID()); + trackData.clAvailTOF = uint16_t(t0forTOFres); } else { trackData.clAvailTOF = 0; } @@ -655,6 +684,7 @@ void TrackInterpolation::interpolateTrack(int iSeed) const auto sec = clusterResiduals[iCl].sec; if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(y) < param::MaxY) && (std::abs(z) < param::MaxZ) && (std::abs(tgPhi) < param::MaxTgSlp)) { mClRes.emplace_back(dy, dz, tgPhi, y, z, iRow, sec); + mDetInfoRes.emplace_back().setTPC(mCacheDEDX[iRow].first, mCacheDEDX[iRow].second); // qtot, qmax ++nClValidated; } else { ++mRejectedResiduals; @@ -662,6 +692,30 @@ void TrackInterpolation::interpolateTrack(int iSeed) } trackData.clIdx.setEntries(nClValidated); + // store multiplicity info + for (int ist = 0; ist < NSTACKS; ist++) { + int mltBinMin = 0x7ffff, mltBinMax = -1, prevBin = -1; + for (int ir = STACKROWS[ist]; ir < STACKROWS[ist + 1]; ir++) { + if (multBins[ir] != prevBin && multBins[ir] > 0) { // there is a cluster different from previous one + prevBin = multBins[ir]; + if (multBins[ir] > mltBinMax) { + mltBinMax = multBins[ir]; + } + if (multBins[ir] < mltBinMin) { + mltBinMin = multBins[ir]; + } + } + } + if (--mltBinMin >= 0) { // we were offsetting bin IDs by 1! + float avMlt = 0; + for (int ib = mltBinMin; ib < mltBinMax; ib++) { + avMlt += mTPCParam->occupancyMap[ib]; + } + avMlt /= (mltBinMax - mltBinMin); + trackData.setMultStack(avMlt, ist); + } + } + bool stopPropagation = !mExtDetResid; if (!stopPropagation) { // do we have TRD residuals to add? @@ -670,7 +724,7 @@ void TrackInterpolation::interpolateTrack(int iSeed) const auto& trkTRD = mRecoCont->getITSTPCTRDTrack(gidTable[GTrackID::ITSTPCTRD]); for (int iLayer = 0; iLayer < o2::trd::constants::NLAYER; iLayer++) { std::array trkltTRDYZ{}; - int res = processTRDLayer(trkTRD, iLayer, trkWork, &trkltTRDYZ, nullptr, &trackData); + int res = processTRDLayer(trkTRD, iLayer, trkWork, &trkltTRDYZ, nullptr, &trackData, &trkl64, &trklCalib); if (res == -1) { // no traklet on this layer continue; } @@ -684,6 +738,7 @@ void TrackInterpolation::interpolateTrack(int iSeed) auto dz = trkltTRDYZ[1] - trkWork.getZ(); if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWork.getY()) < param::MaxY) && (std::abs(trkWork.getZ()) < param::MaxZ) && (std::abs(tgPhi) < param::MaxTgSlp)) { mClRes.emplace_back(dy, dz, tgPhi, trkWork.getY(), trkWork.getZ(), 160 + iLayer, o2::math_utils::angle2Sector(trkWork.getAlpha()), (short)res); + mDetInfoRes.emplace_back().setTRD(trkl64.getQ0(), trkl64.getQ1(), trkl64.getQ2(), trklCalib.getDy()); // q0,q1,q2,slope trackData.nExtDetResid++; } } @@ -710,8 +765,16 @@ void TrackInterpolation::interpolateTrack(int iSeed) float tgPhi = trkWork.getSnp() / std::sqrt((1.f - trkWork.getSnp()) * (1.f + trkWork.getSnp())); auto dy = clTOFxyz[1] - trkWork.getY(); auto dz = clTOFxyz[2] - trkWork.getZ(); + // get seeding track time + if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWork.getY()) < param::MaxY) && (std::abs(trkWork.getZ()) < param::MaxZ) && (std::abs(tgPhi) < param::MaxTgSlp)) { mClRes.emplace_back(dy, dz, tgPhi, trkWork.getY(), trkWork.getZ(), 170, clTOF.getCount(), clTOF.getPadInSector()); + // get seeding track time + if (!gidTable[GTrackID::ITSTPC].isIndexSet()) { + LOGP(fatal, "ITS-TPC seed index is not set for TOF track"); + } + float tdif = static_cast(clTOF.getTime() - t0forTOF); // time in \mus wrt interaction time0 + mDetInfoRes.emplace_back().setTOF(tdif * 1e-6); trackData.nExtDetResid++; } break; @@ -738,6 +801,7 @@ void TrackInterpolation::interpolateTrack(int iSeed) auto dz = cls.getZ() - trkWorkITS.getZ(); if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWorkITS.getY()) < param::MaxY) && (std::abs(trkWorkITS.getZ()) < param::MaxZ) && (std::abs(tgPhi) < param::MaxTgSlp)) { mClRes.emplace_back(dy, dz, tgPhi, trkWorkITS.getY(), trkWorkITS.getZ(), 180 + geom->getLayer(cls.getSensorID()), -1, cls.getSensorID()); + mDetInfoRes.emplace_back(); // empty placeholder trackData.nExtDetResid++; } } @@ -759,6 +823,11 @@ void TrackInterpolation::interpolateTrack(int iSeed) if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWorkITS.getY()) < param::MaxY) && (std::abs(trkWorkITS.getZ()) < param::MaxZ) && abs(xv) < param::MaxVtxX) { short compXV = static_cast(xv * 0x7fff / param::MaxVtxX); mClRes.emplace_back(dy, dz, alpha / TMath::Pi(), trkWorkITS.getY(), trkWorkITS.getZ(), 190, -1, compXV); + if (!gidTable[GTrackID::ITSTPC].isIndexSet()) { + LOGP(fatal, "ITS-TPC seed index is not set for TOF track"); + } + float tdif = pv.getTimeStamp().getTimeStamp() - mRecoCont->getTPCITSTrack(gidTable[GTrackID::ITSTPC]).getTimeMUS().getTimeStamp(); + mDetInfoRes.emplace_back().setPV(tdif); // time in \mus wrt seeding ITS-TPC track trackData.nExtDetResid++; } } @@ -767,7 +836,7 @@ void TrackInterpolation::interpolateTrack(int iSeed) } mGIDsSuccess.push_back(mGIDs[iSeed]); - mTrackDataCompact.emplace_back(trackData.clIdx.getFirstEntry(), nClValidated, mGIDs[iSeed].getSource(), trackData.nExtDetResid); + mTrackDataCompact.emplace_back(trackData.clIdx.getFirstEntry(), trackData.multStack, nClValidated, mGIDs[iSeed].getSource(), trackData.nExtDetResid); mTrackData.push_back(std::move(trackData)); if (mDumpTrackPoints) { (*trackDataExtended).clIdx.setEntries(nClValidated); @@ -785,7 +854,8 @@ void TrackInterpolation::interpolateTrack(int iSeed) } int TrackInterpolation::processTRDLayer(const o2::trd::TrackTRD& trkTRD, int iLayer, o2::track::TrackParCov& trkWork, - std::array* trkltTRDYZ, std::array* trkltTRDCov, TrackData* trkData) + std::array* trkltTRDYZ, std::array* trkltTRDCov, TrackData* trkData, + o2::trd::Tracklet64* trk64, o2::trd::CalibratedTracklet* trkCalib) { // return chamber ID (0:539) in case of successful processing, -1 if there is no TRD tracklet at given layer, -2 if processing failed int trkltIdx = trkTRD.getTrackletIndex(iLayer); @@ -827,6 +897,12 @@ int TrackInterpolation::processTRDLayer(const o2::trd::TrackTRD& trkTRD, int iLa trkData->TRDTrkltSlope[iLayer] = slope * 0x7fff / param::MaxTRDSlope; } } + if (trk64) { + *trk64 = trdTrklt; + } + if (trkCalib) { + *trkCalib = trdSP; + } return trkltDet; } @@ -836,6 +912,8 @@ void TrackInterpolation::extrapolateTrack(int iSeed) LOGP(debug, "Starting track extrapolation for GID {}", mGIDs[iSeed].asString()); const auto& gidTable = mGIDtables[iSeed]; TrackData trackData; + o2::trd::Tracklet64 trkl64; + o2::trd::CalibratedTracklet trklCalib; std::unique_ptr trackDataExtended; std::vector clusterResiduals; trackData.clIdx.setFirstEntry(mClRes.size()); @@ -866,6 +944,8 @@ void TrackInterpolation::extrapolateTrack(int iSeed) unsigned short rowPrev = 0; // used to calculate dRow of two consecutive cluster residuals unsigned short nMeasurements = 0; uint8_t clRowPrev = constants::MAXGLOBALPADROW; // used to identify and skip split clusters on the same pad row + std::array, constants::MAXGLOBALPADROW> mCacheDEDX{}; + std::array multBins{}; for (int iCl = trkTPC.getNClusterReferences(); iCl--;) { uint8_t sector, row; uint32_t clusterIndexInRow; @@ -897,10 +977,14 @@ void TrackInterpolation::extrapolateTrack(int iSeed) const auto tz = trkWork.getZ(); const auto snp = trkWork.getSnp(); const auto sec = sector; - clusterResiduals.emplace_back(dY, dZ, ty, tz, snp, sec, row - rowPrev); - + mCacheDEDX[row].first = cl.getQtot(); + mCacheDEDX[row].second = cl.getQmax(); rowPrev = row; + int imb = int(cl.getTime() * mNTPCOccBinLengthInv); + if (imb < mTPCParam->occupancyMapSize) { + multBins[row] = 1 + std::max(0, imb); + } ++nMeasurements; } @@ -937,6 +1021,7 @@ void TrackInterpolation::extrapolateTrack(int iSeed) const auto z = clusterResiduals[iCl].z; if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(y) < param::MaxY) && (std::abs(z) < param::MaxZ) && (std::abs(tgPhi) < param::MaxTgSlp)) { mClRes.emplace_back(dy, dz, tgPhi, y, z, iRow, clusterResiduals[iCl].sec); + mDetInfoRes.emplace_back().setTPC(mCacheDEDX[iRow].first, mCacheDEDX[iRow].second); // qtot, qmax ++nClValidated; } else { ++mRejectedResiduals; @@ -944,6 +1029,30 @@ void TrackInterpolation::extrapolateTrack(int iSeed) } trackData.clIdx.setEntries(nClValidated); + // store multiplicity info + for (int ist = 0; ist < NSTACKS; ist++) { + int mltBinMin = 0x7ffff, mltBinMax = -1, prevBin = -1; + for (int ir = STACKROWS[ist]; ir < STACKROWS[ist + 1]; ir++) { + if (multBins[ir] != prevBin && multBins[ir] > 0) { // there is a cluster + prevBin = multBins[ir]; + if (multBins[ir] > mltBinMax) { + mltBinMax = multBins[ir]; + } + if (multBins[ir] < mltBinMin) { + mltBinMin = multBins[ir]; + } + } + } + if (--mltBinMin >= 0) { // we were offsetting bin IDs by 1! + float avMlt = 0; + for (int ib = mltBinMin; ib < mltBinMax; ib++) { + avMlt += mTPCParam->occupancyMap[ib]; + } + avMlt /= (mltBinMax - mltBinMin); + trackData.setMultStack(avMlt, ist); + } + } + bool stopPropagation = !mExtDetResid; if (!stopPropagation) { // do we have TRD residuals to add? @@ -955,7 +1064,7 @@ void TrackInterpolation::extrapolateTrack(int iSeed) trackData.nTrkltsTRD = trkTRD.getNtracklets(); for (int iLayer = 0; iLayer < o2::trd::constants::NLAYER; iLayer++) { std::array trkltTRDYZ{}; - int res = processTRDLayer(trkTRD, iLayer, trkWork, &trkltTRDYZ, nullptr, &trackData); + int res = processTRDLayer(trkTRD, iLayer, trkWork, &trkltTRDYZ, nullptr, &trackData, &trkl64, &trklCalib); if (res == -1) { // no traklet on this layer continue; } @@ -970,6 +1079,7 @@ void TrackInterpolation::extrapolateTrack(int iSeed) const auto sec = clusterResiduals[iCl].sec; if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWork.getY()) < param::MaxY) && (std::abs(trkWork.getZ()) < param::MaxZ) && (std::abs(tgPhi) < param::MaxTgSlp)) { mClRes.emplace_back(dy, dz, tgPhi, trkWork.getY(), trkWork.getZ(), 160 + iLayer, o2::math_utils::angle2Sector(trkWork.getAlpha()), (short)res); + mDetInfoRes.emplace_back().setTRD(trkl64.getQ0(), trkl64.getQ1(), trkl64.getQ2(), trklCalib.getDy()); // q0,q1,q2,slope trackData.nExtDetResid++; } } @@ -979,8 +1089,12 @@ void TrackInterpolation::extrapolateTrack(int iSeed) trackData.clAvailTOF = 0; while (gidTableFull[GTrackID::TOF].isIndexSet() && !stopPropagation) { const auto& tofMatch = mRecoCont->getTOFMatch(gidFull); - trackData.deltaTOF = tofMatch.getSignal() - tofMatch.getFT0Best() - tofMatch.getLTIntegralOut().getTOF(trkTPC.getPID().getID()); - trackData.clAvailTOF = uint16_t(tofMatch.getFT0BestRes()); + ULong64_t bclongtof = (tofMatch.getSignal() - 10000) * o2::tof::Geo::BC_TIME_INPS_INV; + double t0forTOF = tofMatch.getFT0Best(); // setting t0 for TOF + float t0forTOFwithinBC = t0forTOF - bclongtof * o2::tof::Geo::BC_TIME_INPS; + float t0forTOFres = tofMatch.getFT0BestRes(); + trackData.deltaTOF = tofMatch.getSignal() - t0forTOF - tofMatch.getLTIntegralOut().getTOF(trkTPC.getPID().getID()); + trackData.clAvailTOF = uint16_t(t0forTOFres); const auto& clTOF = mRecoCont->getTOFClusters()[gidTableFull[GTrackID::TOF]]; const float clTOFAlpha = o2::math_utils::sector2Angle(clTOF.getCount()); float clTOFxyz[3] = {clTOF.getX(), clTOF.getY(), clTOF.getZ()}; @@ -1002,6 +1116,13 @@ void TrackInterpolation::extrapolateTrack(int iSeed) auto dz = clTOFxyz[2] - trkWork.getZ(); if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWork.getY()) < param::MaxY) && (std::abs(trkWork.getZ()) < param::MaxZ) && (std::abs(tgPhi) < param::MaxTgSlp)) { mClRes.emplace_back(dy, dz, tgPhi, trkWork.getY(), trkWork.getZ(), 170, clTOF.getCount(), clTOF.getPadInSector()); + // get seeding track time + if (!gidTableFull[GTrackID::ITSTPC].isIndexSet()) { + LOGP(fatal, "ITS-TPC seed index is not set for TOF track"); + } + + float tdif = static_cast(clTOF.getTime() - t0forTOF); // time in \mus wrt interaction time0 + mDetInfoRes.emplace_back().setTOF(tdif * 1e-6); // time in \mus wrt seeding ITS-TPC track trackData.nExtDetResid++; } break; @@ -1028,6 +1149,7 @@ void TrackInterpolation::extrapolateTrack(int iSeed) auto dz = cls.getZ() - trkWorkITS.getZ(); if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWorkITS.getY()) < param::MaxY) && (std::abs(trkWorkITS.getZ()) < param::MaxZ) && (std::abs(tgPhi) < param::MaxTgSlp)) { mClRes.emplace_back(dy, dz, tgPhi, trkWorkITS.getY(), trkWorkITS.getZ(), 180 + geom->getLayer(cls.getSensorID()), -1, cls.getSensorID()); + mDetInfoRes.emplace_back(); // empty placeholder trackData.nExtDetResid++; } } @@ -1049,6 +1171,11 @@ void TrackInterpolation::extrapolateTrack(int iSeed) if ((std::abs(dy) < param::MaxResid) && (std::abs(dz) < param::MaxResid) && (std::abs(trkWorkITS.getY()) < param::MaxY) && (std::abs(trkWorkITS.getZ()) < param::MaxZ) && abs(xv) < param::MaxVtxX) { short compXV = static_cast(xv * 0x7fff / param::MaxVtxX); mClRes.emplace_back(dy, dz, alpha / TMath::Pi(), trkWorkITS.getY(), trkWorkITS.getZ(), 190, -1, compXV); + if (!gidTableFull[GTrackID::ITSTPC].isIndexSet()) { + LOGP(fatal, "ITS-TPC seed index is not set for TOF track"); + } + float tdif = pv.getTimeStamp().getTimeStamp() - mRecoCont->getTPCITSTrack(gidTableFull[GTrackID::ITSTPC]).getTimeMUS().getTimeStamp(); + mDetInfoRes.emplace_back().setPV(tdif); // time in \mus wrt seeding ITS-TPC track trackData.nExtDetResid++; } } @@ -1057,7 +1184,7 @@ void TrackInterpolation::extrapolateTrack(int iSeed) } mTrackData.push_back(std::move(trackData)); mGIDsSuccess.push_back(mGIDs[iSeed]); - mTrackDataCompact.emplace_back(trackData.clIdx.getFirstEntry(), nClValidated, mGIDs[iSeed].getSource(), trackData.nExtDetResid); + mTrackDataCompact.emplace_back(trackData.clIdx.getFirstEntry(), trackData.multStack, nClValidated, mGIDs[iSeed].getSource(), trackData.nExtDetResid); if (mDumpTrackPoints) { (*trackDataExtended).clIdx.setEntries(nClValidated); (*trackDataExtended).nExtDetResid = trackData.nExtDetResid; @@ -1445,6 +1572,7 @@ void TrackInterpolation::reset() mTrackDataCompact.clear(); mTrackDataExtended.clear(); mClRes.clear(); + mDetInfoRes.clear(); mTrackDataUnfiltered.clear(); mClResUnfiltered.clear(); mGIDsSuccess.clear(); From 0df45c42929034ad639a89a0618896090012270a Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Thu, 25 Sep 2025 15:57:50 +0200 Subject: [PATCH 121/234] Implementation of TPC loopers in O2 --- Generators/CMakeLists.txt | 10 + Generators/include/Generators/Generator.h | 13 + Generators/include/Generators/TPCLoopers.h | 148 ++++++ .../include/Generators/TPCLoopersParam.h | 54 ++ Generators/share/TPCLoopers/README.md | 79 +++ .../share/TPCLoopers/ScalerComptonParams.json | 28 + .../share/TPCLoopers/ScalerPairParams.json | 34 ++ .../share/TPCLoopers/gaussian_params.csv | 4 + .../share/TPCLoopers/poisson_params.csv | 3 + Generators/src/Generator.cxx | 184 +++++++ Generators/src/GeneratorsLinkDef.h | 4 + Generators/src/TPCLoopers.cxx | 486 ++++++++++++++++++ Generators/src/TPCLoopersParam.cxx | 15 + prodtests/full_system_test.sh | 37 +- 14 files changed, 1095 insertions(+), 4 deletions(-) create mode 100644 Generators/include/Generators/TPCLoopers.h create mode 100644 Generators/include/Generators/TPCLoopersParam.h create mode 100644 Generators/share/TPCLoopers/README.md create mode 100644 Generators/share/TPCLoopers/ScalerComptonParams.json create mode 100644 Generators/share/TPCLoopers/ScalerPairParams.json create mode 100644 Generators/share/TPCLoopers/gaussian_params.csv create mode 100644 Generators/share/TPCLoopers/poisson_params.csv create mode 100644 Generators/src/TPCLoopers.cxx create mode 100644 Generators/src/TPCLoopersParam.cxx diff --git a/Generators/CMakeLists.txt b/Generators/CMakeLists.txt index 02caa63df0d43..287536ff118f7 100644 --- a/Generators/CMakeLists.txt +++ b/Generators/CMakeLists.txt @@ -41,6 +41,8 @@ o2_add_library(Generators src/GeneratorTParticleParam.cxx src/GeneratorService.cxx src/FlowMapper.cxx + src/TPCLoopers.cxx + src/TPCLoopersParam.cxx $<$:src/GeneratorPythia8.cxx> $<$:src/DecayerPythia8.cxx> $<$:src/GeneratorPythia8Param.cxx> @@ -53,6 +55,7 @@ o2_add_library(Generators PUBLIC_LINK_LIBRARIES FairRoot::Base O2::SimConfig O2::CommonUtils O2::DetectorsBase O2::ZDCBase O2::SimulationDataFormat ${pythiaTarget} ${hepmcTarget} FairRoot::Gen + onnxruntime::onnxruntime TARGETVARNAME targetName) if(pythia_FOUND) @@ -63,6 +66,8 @@ if(HepMC3_FOUND) target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_HEPMC3) endif() +target_compile_definitions(${targetName} PUBLIC GENERATORS_WITH_TPCLOOPERS) + set(headers include/Generators/Generator.h include/Generators/Trigger.h @@ -88,6 +93,10 @@ set(headers include/Generators/FlowMapper.h ) +list(APPEND headers + include/Generators/TPCLoopers.h + include/Generators/TPCLoopersParam.h) + if(pythia_FOUND) list(APPEND headers include/Generators/GeneratorPythia8.h @@ -158,4 +167,5 @@ endif() o2_data_file(COPY share/external DESTINATION Generators) o2_data_file(COPY share/egconfig DESTINATION Generators) +o2_data_file(COPY share/TPCLoopers DESTINATION Generators) o2_data_file(COPY share/pythia8 DESTINATION Generators) diff --git a/Generators/include/Generators/Generator.h b/Generators/include/Generators/Generator.h index bd35a00793e2d..3484601aa42bb 100644 --- a/Generators/include/Generators/Generator.h +++ b/Generators/include/Generators/Generator.h @@ -17,6 +17,10 @@ #include "FairGenerator.h" #include "TParticle.h" #include "Generators/Trigger.h" +#ifdef GENERATORS_WITH_TPCLOOPERS +#include "Generators/TPCLoopers.h" +#include "Generators/TPCLoopersParam.h" +#endif #include #include #include @@ -73,6 +77,7 @@ class Generator : public FairGenerator /** methods to override **/ virtual Bool_t generateEvent() = 0; // generates event (in structure internal to generator) virtual Bool_t importParticles() = 0; // fills the mParticles vector (transfer from generator state) + Bool_t finalizeEvent(); // final part of event generation that can be customised using external macros virtual void updateHeader(o2::dataformats::MCEventHeader* eventHeader) {}; Bool_t triggerEvent(); @@ -154,6 +159,8 @@ class Generator : public FairGenerator private: void updateSubGeneratorInformation(o2::dataformats::MCEventHeader* header) const; + // loopers flag + Bool_t mAddTPCLoopers = kFALSE; // Flag is automatically set to true if TPC is in readout detectors, loopers are not vetoed and transport is enabled // collect an ID and a short description of sub-generator entities std::unordered_map mSubGeneratorsIdToDesc; // the current ID of the sub-generator used in the current event (if applicable) @@ -162,6 +169,12 @@ class Generator : public FairGenerator // global static information about (upper limit of) number of events to be generated static unsigned int gTotalNEvents; +#ifdef GENERATORS_WITH_TPCLOOPERS + // Loopers generator instance + std::unique_ptr mTPCLoopersGen = nullptr; + bool initTPCLoopersGen(); +#endif + ClassDefOverride(Generator, 2); }; /** class Generator **/ diff --git a/Generators/include/Generators/TPCLoopers.h b/Generators/include/Generators/TPCLoopers.h new file mode 100644 index 0000000000000..6a1d3ef262e22 --- /dev/null +++ b/Generators/include/Generators/TPCLoopers.h @@ -0,0 +1,148 @@ +// Copyright 2024-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author M+Giacalone - September 2025 + +#ifndef ALICEO2_EVENTGEN_TPCLOOPERS_H_ +#define ALICEO2_EVENTGEN_TPCLOOPERS_H_ + +#ifdef GENERATORS_WITH_TPCLOOPERS +#include +#endif +#include +#include +#include "TRandom3.h" +#include +#include "TParticle.h" + +#ifdef GENERATORS_WITH_TPCLOOPERS +// Static Ort::Env instance for multiple onnx model loading +extern Ort::Env global_env; + +// This class is responsible for loading the scaler parameters from a JSON file +// and applying the inverse transformation to the generated data. +// Inferenced output is scaled (min-max normalization or robust scaling for outlier features) during training, +// so we need to revert this transformation to get physical values. +struct Scaler { + std::vector normal_min; + std::vector normal_max; + std::vector outlier_center; + std::vector outlier_scale; + + void load(const std::string& filename); + + std::vector inverse_transform(const std::vector& input); + + private: + std::vector jsonArrayToVector(const rapidjson::Value& jsonArray); +}; + +// This class loads the ONNX model and generates samples using it. +class ONNXGenerator +{ + public: + ONNXGenerator(Ort::Env& shared_env, const std::string& model_path); + + std::vector generate_sample(); + + private: + Ort::Env& env; + Ort::Session session; + TRandom3 rand_gen; +}; +#endif // GENERATORS_WITH_TPCLOOPERS + +namespace o2 +{ +namespace eventgen +{ + +#ifdef GENERATORS_WITH_TPCLOOPERS +/** + * Generator for TPC Loopers based on pre-trained ONNX models. + * Currently it generates loopers as electron-positron pairs and Compton electrons + * according to specified distributions and parameters. + * This can be extended to other types of background processes in the future (e.g. slow neutron spallation products, saturation tail). + * Multiple configuration options are available: + * - Flat gas: loopers are generated uniformly per event taking a reference value which can be either the LHC orbit time or the average interaction time record interval from the collision context. + * ==> Current automatic setup (default) sets the interaction rate automatically from the collision context and the reference value per orbit is calculated from an external file. + * ==> Number of loopers per orbit can be adjusted via a specific parameter. + * - Poisson + Gaussian sampling: number of loopers are sampled from Poissonian (for pairs) and Gaussian (for Compton electrons) distributions based on provided parameters. + * ==> flat gas must be disabled to use this option. + * - Fixed number of loopers per event + * ==> flat gas must be disabled to use this option and Poissonian/Gaussian parameters file should be set to None + */ +class GenTPCLoopers +{ + public: + GenTPCLoopers(std::string model_pairs = "tpcloopmodel.onnx", std::string model_compton = "tpcloopmodelcompton.onnx", + std::string poisson = "poisson.csv", std::string gauss = "gauss.csv", std::string scaler_pair = "scaler_pair.json", + std::string scaler_compton = "scaler_compton.json"); + + Bool_t generateEvent(); + + Bool_t generateEvent(double time_limit); + + std::vector importParticles(); + + unsigned int PoissonPairs(); + + unsigned int GaussianElectrons(); + + void SetNLoopers(unsigned int nsig_pair, unsigned int nsig_compton); + + void SetMultiplier(const std::array& mult); + + void setFlatGas(Bool_t flat, Int_t number = -1, Int_t nloopers_orbit = -1); + + void setFractionPairs(float fractionPairs); + + void SetRate(const std::string& rateFile, bool isPbPb, int intRate = 50000); + + void SetAdjust(float adjust = 0.f); + + unsigned int getNLoopers() const { return (mNLoopersPairs + mNLoopersCompton); } + + private: + std::unique_ptr mONNX_pair = nullptr; + std::unique_ptr mONNX_compton = nullptr; + std::unique_ptr mScaler_pair = nullptr; + std::unique_ptr mScaler_compton = nullptr; + double mPoisson[3] = {0.0, 0.0, 0.0}; // Mu, Min and Max of Poissonian + double mGauss[4] = {0.0, 0.0, 0.0, 0.0}; // Mean, Std, Min, Max + std::vector> mGenPairs; + std::vector> mGenElectrons; + unsigned int mNLoopersPairs = -1; + unsigned int mNLoopersCompton = -1; + std::array mMultiplier = {1., 1.}; + bool mPoissonSet = false; + bool mGaussSet = false; + // Random number generator + TRandom3 mRandGen; + int mCurrentEvent = 0; // Current event number, used for adaptive loopers + TFile* mContextFile = nullptr; // Input collision context file + o2::steer::DigitizationContext* mCollisionContext = nullptr; // Pointer to the digitization context + std::vector mInteractionTimeRecords; // Interaction time records from collision context + Bool_t mFlatGas = false; // Flag to indicate if flat gas loopers are used + Bool_t mFlatGasOrbit = false; // Flag to indicate if flat gas loopers are per orbit + Int_t mFlatGasNumber = -1; // Number of flat gas loopers per event + double mIntTimeRecMean = 1.0; // Average interaction time record used for the reference + double mTimeLimit = 0.0; // Time limit for the current event + double mTimeEnd = 0.0; // Time limit for the last event + float mLoopsFractionPairs = 0.08; // Fraction of loopers from Pairs + int mInteractionRate = 50000; // Interaction rate in Hz +}; +#endif // GENERATORS_WITH_TPCLOOPERS + +} // namespace eventgen +} // namespace o2 + +#endif // ALICEO2_EVENTGEN_TPCLOOPERS_H_ \ No newline at end of file diff --git a/Generators/include/Generators/TPCLoopersParam.h b/Generators/include/Generators/TPCLoopersParam.h new file mode 100644 index 0000000000000..87e4510d6e617 --- /dev/null +++ b/Generators/include/Generators/TPCLoopersParam.h @@ -0,0 +1,54 @@ +// Copyright 2024-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author M+Giacalone - September 2025 + +#ifndef ALICEO2_EVENTGEN_TPCLOOPERSPARAM_H_ +#define ALICEO2_EVENTGEN_TPCLOOPERSPARAM_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" + +namespace o2 +{ +namespace eventgen +{ + +/** + ** a parameter class/struct to keep the settings of + ** the TPC loopers event-generator and + ** allow the user to modify them + **/ +struct GenTPCLoopersParam : public o2::conf::ConfigurableParamHelper { + bool loopersVeto = false; // if true, no loopers are generated + // Current files are set to custom user CCDB paths, TO BE CHANGED + std::string model_pairs = "ccdb://Users/m/mgiacalo/WGAN_ExtGenPair"; // ONNX model for e+e- pair production + std::string model_compton = "ccdb://Users/m/mgiacalo/WGAN_ExtGenCompton"; // ONNX model for Compton scattering + std::string poisson = "${O2_ROOT}/share/Generators/TPCLoopers/poisson_params.csv"; // file with Poissonian parameters + std::string gauss = "${O2_ROOT}/share/Generators/TPCLoopers/gaussian_params.csv"; // file with Gaussian parameters + std::string scaler_pair = "${O2_ROOT}/share/Generators/TPCLoopers/ScalerPairParams.json"; // file with scaler parameters for e+e- pair production + std::string scaler_compton = "${O2_ROOT}/share/Generators/TPCLoopers/ScalerComptonParams.json"; // file with scaler parameters for Compton scattering + std::string nclxrate = "ccdb://Users/m/mgiacalo/ClustersTrackRatio"; // file with clusters/rate information per orbit + std::string colsys = "PbPb"; // collision system (PbPb or pp) + int intrate = -1; // Automatic IR from collision context if -1, else user-defined interaction rate in Hz + bool flat_gas = true; // if true, the gas density is considered flat in the TPC volume + unsigned int nFlatGasLoopers = 500; // number of loopers to be generated per event in case of flat gas [currently unused, kept for possible future debug developments] + float fraction_pairs = 0.08; // fraction of loopers [currently unused, kept for possible future debug developments] + float multiplier[2] = {1., 1.}; // multiplier for pairs and compton loopers for Poissonian and Gaussian sampling + unsigned int fixedNLoopers[2] = {1, 1}; // fixed number of loopers coming from pairs and compton electrons - valid if flat gas is false and both Poisson and Gaussian params files are empty + float adjust_flatgas = 0.f; // adjustment for the number of flat gas loopers per orbit (in percentage, e.g. -0.1 = -10%) [-1, inf)] + O2ParamDef(GenTPCLoopersParam, "GenTPCLoopers"); +}; + +} // end namespace eventgen +} // end namespace o2 + +#endif // ALICEO2_EVENTGEN_TPCLOOPERSPARAM_H_ diff --git a/Generators/share/TPCLoopers/README.md b/Generators/share/TPCLoopers/README.md new file mode 100644 index 0000000000000..0e0ac858b8809 --- /dev/null +++ b/Generators/share/TPCLoopers/README.md @@ -0,0 +1,79 @@ +# TPC Loopers Generator - Parameter Files + +This directory contains parameter files used by the TPC Loopers event generator in ALICE O2. + +## Overview + +The TPC Loopers generator uses pre-trained ONNX models to generate realistic looper particles based on machine learning models trained on full GEANT4 slow neutron transport simulations. The parameter files in this directory provide: +- Example statistical distribution parameters for sampling the number of loopers per event +- **Mandatory** scaling parameters for transforming the ONNX model outputs to physical values + +## Files Description + +### Statistical Sampling Parameters + +The files provided in the folder are examples based on the training dataset. + +#### `gaussian_params.csv` +Parameters for Gaussian distribution used to sample the number of Compton electrons per event. + +**Format:** Four values (one per line) +1. Mean (μ) +2. Standard deviation (σ) +3. Minimum value +4. Maximum value + +#### `poisson_params.csv` +Parameters for Poisson distribution used to sample the number of electron-positron pairs per event. + +**Format:** Three values (one per line) +1. Lambda (λ) parameter +2. Minimum value +3. Maximum value + +### Scaler Parameters + +These JSON files contain the parameters for inverse transformation of the ONNX models output. They should be kept as they are +unless a new version of the models is released. + +#### `ScalerComptonParams.json` +Scaler parameters for Compton electron generation model. + +**Structure:** +```json +{ + "normal": { + "min": [array of 5 min values for min-max normalization], + "max": [array of 5 max values for min-max normalization] + }, + "outlier": { + "center": [array of 2 center values for robust scaling], + "scale": [array of 2 scale values for robust scaling] + } +} +``` + +- **normal**: Min-max normalization parameters for standard features (`Px`, `Py`, `Pz`, `VertexCoordinatesX`, `VertexCoordinatesY`) +- **outlier**: Robust scaler parameters (center and scale) for outlier features (`VertexCoordinatesZ`,`time`) + +#### `ScalerPairParams.json` +Scaler parameters for electron-positron pair generation model. + +**Structure:** +```json +{ + "normal": { + "min": [array of 8 min values for min-max normalization], + "max": [array of 8 max values for min-max normalization] + }, + "outlier": { + "center": [array of 2 center values for robust scaling], + "scale": [array of 2 scale values for robust scaling] + } +} +``` + +- **normal**: Min-max normalization parameters for standard features (`Px_e`, `Py_e`, `Pz_e`,`Px_p`, `Py_p`, `Pz_p`, `VertexCoordinatesX`, `VertexCoordinatesY`) +- **outlier**: Robust scaler parameters (center and scale) for outlier features (`VertexCoordinatesZ`,`time`) +--- +*Author: M. Giacalone - September 2025* diff --git a/Generators/share/TPCLoopers/ScalerComptonParams.json b/Generators/share/TPCLoopers/ScalerComptonParams.json new file mode 100644 index 0000000000000..157647fee2db7 --- /dev/null +++ b/Generators/share/TPCLoopers/ScalerComptonParams.json @@ -0,0 +1,28 @@ +{ + "normal": { + "min": [ + -0.0108811147511005, + -0.0098758740350604, + -0.0103233363479375, + -260.0542297363281, + -259.80059814453125 + ], + "max": [ + 0.0108060473576188, + 0.0103057539090514, + 0.0106524610891938, + 260.0343933105469, + 259.62890625 + ] + }, + "outlier": { + "center": [ + -71.39387130737305, + 96791.23828125 + ], + "scale": [ + 265.9389114379883, + 230762.30981445312 + ] + } +} \ No newline at end of file diff --git a/Generators/share/TPCLoopers/ScalerPairParams.json b/Generators/share/TPCLoopers/ScalerPairParams.json new file mode 100644 index 0000000000000..57cdac421d3f6 --- /dev/null +++ b/Generators/share/TPCLoopers/ScalerPairParams.json @@ -0,0 +1,34 @@ +{ + "normal": { + "min": [ + -0.0073022879660129, + -0.0077305701561272, + -0.0076750442385673, + -0.0082916170358657, + -0.0079681202769279, + -0.0077468422241508, + -255.6164093017578, + -252.9441680908203 + ], + "max": [ + 0.007688719779253, + 0.0077241472899913, + 0.0075828479602932, + 0.00813714787364, + 0.0083825681358575, + 0.0073839174583554, + 256.2904968261719, + 253.4925842285156 + ] + }, + "outlier": { + "center": [ + -79.66580963134766, + 141535.640625 + ], + "scale": [ + 250.8921127319336, + 222363.16015625 + ] + } +} \ No newline at end of file diff --git a/Generators/share/TPCLoopers/gaussian_params.csv b/Generators/share/TPCLoopers/gaussian_params.csv new file mode 100644 index 0000000000000..8e07c22dd30bf --- /dev/null +++ b/Generators/share/TPCLoopers/gaussian_params.csv @@ -0,0 +1,4 @@ +9.611554230339172022e+01 +1.963570744941765867e+01 +4.300000000000000000e+01 +1.690000000000000000e+02 diff --git a/Generators/share/TPCLoopers/poisson_params.csv b/Generators/share/TPCLoopers/poisson_params.csv new file mode 100644 index 0000000000000..ef26bd973d34c --- /dev/null +++ b/Generators/share/TPCLoopers/poisson_params.csv @@ -0,0 +1,3 @@ +3.165383056343737511e+00 +1.000000000000000000e+00 +1.200000000000000000e+01 diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 9204ede98215e..465a8ffb7ee22 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -17,11 +17,16 @@ #include "SimulationDataFormat/MCEventHeader.h" #include "SimulationDataFormat/ParticleStatus.h" #include "SimulationDataFormat/MCGenProperties.h" +#include #include "FairPrimaryGenerator.h" #include #include #include "TClonesArray.h" #include "TParticle.h" +#include "TSystem.h" +#include "TGrid.h" +#include "CCDB/BasicCCDBManager.h" +#include namespace o2 { @@ -39,6 +44,25 @@ Generator::Generator() : FairGenerator("ALICEo2", "ALICEo2 Generator"), /** default constructor **/ mThisInstanceID = Generator::InstanceCounter; Generator::InstanceCounter++; +#ifdef GENERATORS_WITH_TPCLOOPERS + const auto& simConfig = o2::conf::SimConfig::Instance(); + const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); + if (!loopersParam.loopersVeto) { + bool transport = (simConfig.getMCEngine() != "O2TrivialMCEngine"); + if (transport) { + bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); + if (tpcActive) { + if (initTPCLoopersGen()) { + mAddTPCLoopers = kTRUE; + } + } else { + LOG(info) << "TPC not active in readout detectors: loopers fast generator disabled."; + } + } + } else { + LOG(info) << "Loopers fast generator turned OFF with veto flag."; + } +#endif } /*****************************************************************/ @@ -49,7 +73,126 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na /** constructor **/ mThisInstanceID = Generator::InstanceCounter; Generator::InstanceCounter++; +#ifdef GENERATORS_WITH_TPCLOOPERS + const auto& simConfig = o2::conf::SimConfig::Instance(); + const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); + if (!loopersParam.loopersVeto) { + bool transport = (simConfig.getMCEngine() != "O2TrivialMCEngine"); + if (transport) { + bool tpcActive = (std::find(simConfig.getReadoutDetectors().begin(), simConfig.getReadoutDetectors().end(), "TPC") != simConfig.getReadoutDetectors().end()); + if (tpcActive) { + if (initTPCLoopersGen()) { + mAddTPCLoopers = kTRUE; + } + } else { + LOG(info) << "TPC not active in readout detectors: loopers fast generator disabled."; + } + } + } else { + LOG(info) << "Loopers fast generator turned OFF with veto flag."; + } +#endif +} + +/*****************************************************************/ +#ifdef GENERATORS_WITH_TPCLOOPERS +bool Generator::initTPCLoopersGen() +{ + // Expand all environment paths + const auto& loopersParam = o2::eventgen::GenTPCLoopersParam::Instance(); + std::string model_pairs = gSystem->ExpandPathName(loopersParam.model_pairs.c_str()); + std::string model_compton = gSystem->ExpandPathName(loopersParam.model_compton.c_str()); + std::string nclxrate = gSystem->ExpandPathName(loopersParam.nclxrate.c_str()); + const auto& scaler_pair = gSystem->ExpandPathName(loopersParam.scaler_pair.c_str()); + const auto& scaler_compton = gSystem->ExpandPathName(loopersParam.scaler_compton.c_str()); + const auto& poisson = gSystem->ExpandPathName(loopersParam.poisson.c_str()); + const auto& gauss = gSystem->ExpandPathName(loopersParam.gauss.c_str()); + const auto& flat_gas = loopersParam.flat_gas; + const auto& colsys = loopersParam.colsys; + if (flat_gas) { + if (colsys != "PbPb" && colsys != "pp") { + LOG(warning) << "Automatic background loopers configuration supports only 'pp' and 'PbPb' systems."; + LOG(warning) << "Fast loopers generator will remain OFF."; + return kFALSE; + } + bool isContext = std::filesystem::exists("collisioncontext.root"); + if (!isContext) { + LOG(warning) << "Warning: No collisioncontext.root file found!"; + LOG(warning) << "Loopers will be kept OFF."; + return kFALSE; + } + } + std::array multiplier = {loopersParam.multiplier[0], loopersParam.multiplier[1]}; + unsigned int nLoopersPairs = loopersParam.fixedNLoopers[0]; + unsigned int nLoopersCompton = loopersParam.fixedNLoopers[1]; + const std::array models = {model_pairs, model_compton, nclxrate}; + const std::array local_names = {"WGANpair.onnx", "WGANcompton.onnx", "nclxrate.root"}; + const std::array isAlien = {models[0].starts_with("alien://"), models[1].starts_with("alien://"), models[2].starts_with("alien://")}; + const std::array isCCDB = {models[0].starts_with("ccdb://"), models[1].starts_with("ccdb://"), models[2].starts_with("ccdb://")}; + if (std::any_of(isAlien.begin(), isAlien.end(), [](bool v) { return v; })) { + if (!gGrid) { + TGrid::Connect("alien://"); + if (!gGrid) { + LOG(fatal) << "AliEn connection failed, check token."; + exit(1); + } + } + for (size_t i = 0; i < models.size(); ++i) { + if (isAlien[i] && !TFile::Cp(models[i].c_str(), local_names[i].c_str())) { + LOG(fatal) << "Error: Model file " << models[i] << " does not exist!"; + exit(1); + } + } + } + if (std::any_of(isCCDB.begin(), isCCDB.end(), [](bool v) { return v; })) { + auto& ccdb = o2::ccdb::BasicCCDBManager::instance(); + ccdb.setURL("http://alice-ccdb.cern.ch"); + // Get underlying CCDB API from BasicCCDBManager + auto& ccdb_api = ccdb.getCCDBAccessor(); + for (size_t i = 0; i < models.size(); ++i) { + if (isCCDB[i]) { + auto model_path = models[i].substr(7); // Remove "ccdb://" + // Treat filename if provided in the CCDB path + auto extension = model_path.find(".onnx"); + if (extension != std::string::npos) { + auto last_slash = model_path.find_last_of('/'); + model_path = model_path.substr(0, last_slash); + } + std::map filter; + if (!ccdb_api.retrieveBlob(model_path, "./", filter, o2::ccdb::getCurrentTimestamp(), false, local_names[i].c_str())) { + LOG(fatal) << "Error: issues in retrieving " << model_path << " from CCDB!"; + exit(1); + } + } + } + } + model_pairs = isAlien[0] || isCCDB[0] ? local_names[0] : model_pairs; + model_compton = isAlien[1] || isCCDB[1] ? local_names[1] : model_compton; + nclxrate = isAlien[2] || isCCDB[2] ? local_names[2] : nclxrate; + try { + // Create the TPC loopers generator with the provided parameters + mTPCLoopersGen = std::make_unique(model_pairs, model_compton, poisson, gauss, scaler_pair, scaler_compton); + const auto& intrate = loopersParam.intrate; + // Configure the generator with flat gas loopers defined per orbit with clusters/track info + // If intrate is negative (default), automatic IR from collisioncontext.root will be used + if (flat_gas) { + mTPCLoopersGen->SetRate(nclxrate, (colsys == "PbPb") ? true : false, intrate); + mTPCLoopersGen->SetAdjust(loopersParam.adjust_flatgas); + } else { + // Otherwise, Poisson+Gauss sampling or fixed number of loopers per event will be used + // Multiplier is applied only with distribution sampling + // This configuration can be used for testing purposes, in all other cases flat gas is recommended + mTPCLoopersGen->SetNLoopers(nLoopersPairs, nLoopersCompton); + mTPCLoopersGen->SetMultiplier(multiplier); + } + LOG(info) << "TPC Loopers generator initialized successfully"; + } catch (const std::exception& e) { + LOG(error) << "Failed to initialize TPC Loopers generator: " << e.what(); + mTPCLoopersGen.reset(); + } + return kTRUE; } +#endif /*****************************************************************/ @@ -64,6 +207,41 @@ Bool_t /*****************************************************************/ +Bool_t + Generator::finalizeEvent() +{ +#ifdef GENERATORS_WITH_TPCLOOPERS + if (mAddTPCLoopers) { + if (!mTPCLoopersGen) { + LOG(error) << "Loopers generator not initialized"; + return kFALSE; + } + + // Generate loopers using the initialized TPC loopers generator + if (!mTPCLoopersGen->generateEvent()) { + LOG(error) << "Failed to generate loopers event"; + return kFALSE; + } + if (mTPCLoopersGen->getNLoopers() == 0) { + LOG(warning) << "No loopers generated for this event"; + return kTRUE; + } + const auto& looperParticles = mTPCLoopersGen->importParticles(); + if (looperParticles.empty()) { + LOG(error) << "Failed to import loopers particles"; + return kFALSE; + } + // Append the generated looper particles to the main particle list + mParticles.insert(mParticles.end(), looperParticles.begin(), looperParticles.end()); + + LOG(debug) << "Added " << looperParticles.size() << " looper particles"; + } +#endif + return kTRUE; +} + +/*****************************************************************/ + Bool_t Generator::ReadEvent(FairPrimaryGenerator* primGen) { @@ -91,6 +269,12 @@ Bool_t return kFALSE; } + /** Event finalization**/ + if (!finalizeEvent()) { + LOG(error) << "ReadEvent failed in finalizeEvent"; + return kFALSE; + } + if (mSubGeneratorsIdToDesc.empty() && mSubGeneratorId > -1) { LOG(fatal) << "ReadEvent failed because no SubGenerator description given"; } diff --git a/Generators/src/GeneratorsLinkDef.h b/Generators/src/GeneratorsLinkDef.h index 2b8d42f86bf9b..24b3f2e452498 100644 --- a/Generators/src/GeneratorsLinkDef.h +++ b/Generators/src/GeneratorsLinkDef.h @@ -35,6 +35,10 @@ #pragma link C++ class o2::eventgen::GeneratorFromEventPool + ; #pragma link C++ class o2::eventgen::GeneratorEventPoolParam + ; #pragma link C++ class o2::eventgen::EventPoolGenConfig + ; +#ifdef GENERATORS_WITH_TPCLOOPERS +#pragma link C++ class o2::eventgen::GenTPCLoopers + ; +#pragma link C++ class o2::eventgen::GenTPCLoopersParam + ; +#endif #pragma link C++ class o2::conf::ConfigurableParamPromoter < o2::eventgen::GeneratorEventPoolParam, o2::eventgen::EventPoolGenConfig> + ; #ifdef GENERATORS_WITH_HEPMC3 #pragma link C++ class o2::eventgen::GeneratorHepMC + ; diff --git a/Generators/src/TPCLoopers.cxx b/Generators/src/TPCLoopers.cxx new file mode 100644 index 0000000000000..6e5af7c0c84d8 --- /dev/null +++ b/Generators/src/TPCLoopers.cxx @@ -0,0 +1,486 @@ +// Copyright 2024-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author M+Giacalone - September 2025 + +#include "Generators/TPCLoopers.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsRaw/HBFUtils.h" +#include "TF1.h" +#include +#include +#include "SimulationDataFormat/MCGenProperties.h" +#include +#include +#include "TDatabasePDG.h" + +// Static Ort::Env instance for multiple onnx model loading +Ort::Env global_env(ORT_LOGGING_LEVEL_WARNING, "GlobalEnv"); + +// This class is responsible for loading the scaler parameters from a JSON file +// and applying the inverse transformation to the generated data. + +void Scaler::load(const std::string& filename) +{ + std::ifstream file(filename); + if (!file.is_open()) { + throw std::runtime_error("Error: Could not open scaler file!"); + } + + std::string json_str((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + file.close(); + + rapidjson::Document doc; + doc.Parse(json_str.c_str()); + + if (doc.HasParseError()) { + throw std::runtime_error("Error: JSON parsing failed!"); + } + + normal_min = jsonArrayToVector(doc["normal"]["min"]); + normal_max = jsonArrayToVector(doc["normal"]["max"]); + outlier_center = jsonArrayToVector(doc["outlier"]["center"]); + outlier_scale = jsonArrayToVector(doc["outlier"]["scale"]); +} + +std::vector Scaler::inverse_transform(const std::vector& input) +{ + std::vector output; + for (int i = 0; i < input.size(); ++i) { + if (i < input.size() - 2) { + output.push_back(input[i] * (normal_max[i] - normal_min[i]) + normal_min[i]); + } else { + output.push_back(input[i] * outlier_scale[i - (input.size() - 2)] + outlier_center[i - (input.size() - 2)]); + } + } + + return output; +} + +std::vector Scaler::jsonArrayToVector(const rapidjson::Value& jsonArray) +{ + std::vector vec; + for (int i = 0; i < jsonArray.Size(); ++i) { + vec.push_back(jsonArray[i].GetDouble()); + } + return vec; +} + +// This class loads the ONNX model and generates samples using it. + +ONNXGenerator::ONNXGenerator(Ort::Env& shared_env, const std::string& model_path) + : env(shared_env), session(env, model_path.c_str(), Ort::SessionOptions{}) +{ + // Create session options + Ort::SessionOptions session_options; + session = Ort::Session(env, model_path.c_str(), session_options); +} + +std::vector ONNXGenerator::generate_sample() +{ + Ort::AllocatorWithDefaultOptions allocator; + + // Generate a latent vector (z) + std::vector z(100); + for (auto& v : z) { + v = rand_gen.Gaus(0.0, 1.0); + } + + // Prepare input tensor + std::vector input_shape = {1, 100}; + // Get memory information + Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); + + // Create input tensor correctly + Ort::Value input_tensor = Ort::Value::CreateTensor( + memory_info, z.data(), z.size(), input_shape.data(), input_shape.size()); + // Run inference + const char* input_names[] = {"z"}; + const char* output_names[] = {"output"}; + auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_names, &input_tensor, 1, output_names, 1); + + // Extract output + float* output_data = output_tensors.front().GetTensorMutableData(); + // Get the size of the output tensor + auto output_tensor_info = output_tensors.front().GetTensorTypeAndShapeInfo(); + size_t output_data_size = output_tensor_info.GetElementCount(); // Total number of elements in the tensor + std::vector output; + for (int i = 0; i < output_data_size; ++i) { + output.push_back(output_data[i]); + } + + return output; +} + +namespace o2 +{ +namespace eventgen +{ + +GenTPCLoopers::GenTPCLoopers(std::string model_pairs, std::string model_compton, + std::string poisson, std::string gauss, std::string scaler_pair, + std::string scaler_compton) +{ + // Checking if the model files exist and are not empty + std::ifstream model_file[2]; + model_file[0].open(model_pairs); + model_file[1].open(model_compton); + if (!model_file[0].is_open() || model_file[0].peek() == std::ifstream::traits_type::eof()) { + LOG(fatal) << "Error: Pairs model file is empty or does not exist!"; + exit(1); + } + if (!model_file[1].is_open() || model_file[1].peek() == std::ifstream::traits_type::eof()) { + LOG(fatal) << "Error: Compton model file is empty or does not exist!"; + exit(1); + } + model_file[0].close(); + model_file[1].close(); + // Checking if the scaler files exist and are not empty + std::ifstream scaler_file[2]; + scaler_file[0].open(scaler_pair); + scaler_file[1].open(scaler_compton); + if (!scaler_file[0].is_open() || scaler_file[0].peek() == std::ifstream::traits_type::eof()) { + LOG(fatal) << "Error: Pairs scaler file is empty or does not exist!"; + exit(1); + } + if (!scaler_file[1].is_open() || scaler_file[1].peek() == std::ifstream::traits_type::eof()) { + LOG(fatal) << "Error: Compton scaler file is empty or does not exist!"; + exit(1); + } + scaler_file[0].close(); + scaler_file[1].close(); + // Checking if the poisson file exists and it's not empty + if (poisson != "" && poisson != "None" && poisson != "none") { + std::ifstream poisson_file(poisson); + if (!poisson_file.is_open() || poisson_file.peek() == std::ifstream::traits_type::eof()) { + LOG(fatal) << "Error: Poisson file is empty or does not exist!"; + exit(1); + } else { + poisson_file >> mPoisson[0] >> mPoisson[1] >> mPoisson[2]; + poisson_file.close(); + mPoissonSet = true; + } + } + // Checking if the gauss file exists and it's not empty + if (gauss != "" && gauss != "None" && gauss != "none") { + std::ifstream gauss_file(gauss); + if (!gauss_file.is_open() || gauss_file.peek() == std::ifstream::traits_type::eof()) { + LOG(fatal) << "Error: Gauss file is empty or does not exist!"; + exit(1); + } else { + gauss_file >> mGauss[0] >> mGauss[1] >> mGauss[2] >> mGauss[3]; + gauss_file.close(); + mGaussSet = true; + } + } + mONNX_pair = std::make_unique(global_env, model_pairs); + mScaler_pair = std::make_unique(); + mScaler_pair->load(scaler_pair); + mONNX_compton = std::make_unique(global_env, model_compton); + mScaler_compton = std::make_unique(); + mScaler_compton->load(scaler_compton); +} + +Bool_t GenTPCLoopers::generateEvent() +{ + // Clear the vector of pairs + mGenPairs.clear(); + // Clear the vector of compton electrons + mGenElectrons.clear(); + if (mFlatGas) { + unsigned int nLoopers, nLoopersPairs, nLoopersCompton; + LOG(debug) << "mCurrentEvent is " << mCurrentEvent; + LOG(debug) << "Current event time: " << ((mCurrentEvent < mInteractionTimeRecords.size() - 1) ? std::to_string(mInteractionTimeRecords[mCurrentEvent + 1].bc2ns() - mInteractionTimeRecords[mCurrentEvent].bc2ns()) : std::to_string(mTimeEnd - mInteractionTimeRecords[mCurrentEvent].bc2ns())) << " ns"; + LOG(debug) << "Current time offset wrt BC: " << mInteractionTimeRecords[mCurrentEvent].getTimeOffsetWrtBC() << " ns"; + mTimeLimit = (mCurrentEvent < mInteractionTimeRecords.size() - 1) ? mInteractionTimeRecords[mCurrentEvent + 1].bc2ns() - mInteractionTimeRecords[mCurrentEvent].bc2ns() : mTimeEnd - mInteractionTimeRecords[mCurrentEvent].bc2ns(); + // With flat gas the number of loopers are adapted based on time interval widths + // The denominator is either the LHC orbit (if mFlatGasOrbit is true) or the mean interaction time record interval + nLoopers = mFlatGasOrbit ? (mFlatGasNumber * (mTimeLimit / o2::constants::lhc::LHCOrbitNS)) : (mFlatGasNumber * (mTimeLimit / mIntTimeRecMean)); + nLoopersPairs = static_cast(std::round(nLoopers * mLoopsFractionPairs)); + nLoopersCompton = nLoopers - nLoopersPairs; + SetNLoopers(nLoopersPairs, nLoopersCompton); + LOG(info) << "Flat gas loopers: " << nLoopers << " (pairs: " << nLoopersPairs << ", compton: " << nLoopersCompton << ")"; + generateEvent(mTimeLimit); + mCurrentEvent++; + } else { + // Set number of loopers if poissonian params are available + if (mPoissonSet) { + mNLoopersPairs = static_cast(std::round(mMultiplier[0] * PoissonPairs())); + LOG(debug) << "Generated loopers pairs (Poisson): " << mNLoopersPairs; + } + if (mGaussSet) { + mNLoopersCompton = static_cast(std::round(mMultiplier[1] * GaussianElectrons())); + LOG(debug) << "Generated compton electrons (Gauss): " << mNLoopersCompton; + } + // Generate pairs + for (int i = 0; i < mNLoopersPairs; ++i) { + std::vector pair = mONNX_pair->generate_sample(); + // Apply the inverse transformation using the scaler + std::vector transformed_pair = mScaler_pair->inverse_transform(pair); + mGenPairs.push_back(transformed_pair); + } + // Generate compton electrons + for (int i = 0; i < mNLoopersCompton; ++i) { + std::vector electron = mONNX_compton->generate_sample(); + // Apply the inverse transformation using the scaler + std::vector transformed_electron = mScaler_compton->inverse_transform(electron); + mGenElectrons.push_back(transformed_electron); + } + } + return true; +} + +Bool_t GenTPCLoopers::generateEvent(double time_limit) +{ + LOG(info) << "Time constraint for loopers: " << time_limit << " ns"; + // Generate pairs + for (int i = 0; i < mNLoopersPairs; ++i) { + std::vector pair = mONNX_pair->generate_sample(); + // Apply the inverse transformation using the scaler + std::vector transformed_pair = mScaler_pair->inverse_transform(pair); + transformed_pair[9] = gRandom->Uniform(0., time_limit); // Regenerate time, scaling is not needed because time_limit is already in nanoseconds + mGenPairs.push_back(transformed_pair); + } + // Generate compton electrons + for (int i = 0; i < mNLoopersCompton; ++i) { + std::vector electron = mONNX_compton->generate_sample(); + // Apply the inverse transformation using the scaler + std::vector transformed_electron = mScaler_compton->inverse_transform(electron); + transformed_electron[6] = gRandom->Uniform(0., time_limit); // Regenerate time, scaling is not needed because time_limit is already in nanoseconds + mGenElectrons.push_back(transformed_electron); + } + LOG(info) << "Generated Particles with time limit"; + return true; +} + +std::vector GenTPCLoopers::importParticles() +{ + std::vector particles; + const double mass_e = TDatabasePDG::Instance()->GetParticle(11)->Mass(); + const double mass_p = TDatabasePDG::Instance()->GetParticle(-11)->Mass(); + // Get looper pairs from the event + for (auto& pair : mGenPairs) { + double px_e, py_e, pz_e, px_p, py_p, pz_p; + double vx, vy, vz, time; + double e_etot, p_etot; + px_e = pair[0]; + py_e = pair[1]; + pz_e = pair[2]; + px_p = pair[3]; + py_p = pair[4]; + pz_p = pair[5]; + vx = pair[6]; + vy = pair[7]; + vz = pair[8]; + time = pair[9]; + e_etot = TMath::Sqrt(px_e * px_e + py_e * py_e + pz_e * pz_e + mass_e * mass_e); + p_etot = TMath::Sqrt(px_p * px_p + py_p * py_p + pz_p * pz_p + mass_p * mass_p); + // Push the electron + TParticle electron(11, 1, -1, -1, -1, -1, px_e, py_e, pz_e, e_etot, vx, vy, vz, time / 1e9); + electron.SetStatusCode(o2::mcgenstatus::MCGenStatusEncoding(electron.GetStatusCode(), 0).fullEncoding); + electron.SetBit(ParticleStatus::kToBeDone, // + o2::mcgenstatus::getHepMCStatusCode(electron.GetStatusCode()) == 1); + particles.push_back(electron); + // Push the positron + TParticle positron(-11, 1, -1, -1, -1, -1, px_p, py_p, pz_p, p_etot, vx, vy, vz, time / 1e9); + positron.SetStatusCode(o2::mcgenstatus::MCGenStatusEncoding(positron.GetStatusCode(), 0).fullEncoding); + positron.SetBit(ParticleStatus::kToBeDone, // + o2::mcgenstatus::getHepMCStatusCode(positron.GetStatusCode()) == 1); + particles.push_back(positron); + } + // Get compton electrons from the event + for (auto& compton : mGenElectrons) { + double px, py, pz; + double vx, vy, vz, time; + double etot; + px = compton[0]; + py = compton[1]; + pz = compton[2]; + vx = compton[3]; + vy = compton[4]; + vz = compton[5]; + time = compton[6]; + etot = TMath::Sqrt(px * px + py * py + pz * pz + mass_e * mass_e); + // Push the electron + TParticle electron(11, 1, -1, -1, -1, -1, px, py, pz, etot, vx, vy, vz, time / 1e9); + electron.SetStatusCode(o2::mcgenstatus::MCGenStatusEncoding(electron.GetStatusCode(), 0).fullEncoding); + electron.SetBit(ParticleStatus::kToBeDone, // + o2::mcgenstatus::getHepMCStatusCode(electron.GetStatusCode()) == 1); + particles.push_back(electron); + } + + return particles; +} + +unsigned int GenTPCLoopers::PoissonPairs() +{ + unsigned int poissonValue; + do { + // Generate a Poisson-distributed random number with mean mPoisson[0] + poissonValue = mRandGen.Poisson(mPoisson[0]); + } while (poissonValue < mPoisson[1] || poissonValue > mPoisson[2]); // Regenerate if out of range + + return poissonValue; +} + +unsigned int GenTPCLoopers::GaussianElectrons() +{ + unsigned int gaussValue; + do { + // Generate a Normal-distributed random number with mean mGass[0] and stddev mGauss[1] + gaussValue = mRandGen.Gaus(mGauss[0], mGauss[1]); + } while (gaussValue < mGauss[2] || gaussValue > mGauss[3]); // Regenerate if out of range + + return gaussValue; +} + +void GenTPCLoopers::SetNLoopers(unsigned int nsig_pair, unsigned int nsig_compton) +{ + if (mFlatGas) { + mNLoopersPairs = nsig_pair; + mNLoopersCompton = nsig_compton; + } else { + if (mPoissonSet) { + LOG(info) << "Poissonian parameters correctly loaded."; + } else { + mNLoopersPairs = nsig_pair; + } + if (mGaussSet) { + LOG(info) << "Gaussian parameters correctly loaded."; + } else { + mNLoopersCompton = nsig_compton; + } + } +} + +void GenTPCLoopers::SetMultiplier(const std::array& mult) +{ + // Multipliers will work only if the poissonian and gaussian parameters are set + // otherwise they will be ignored + if (mult[0] < 0 || mult[1] < 0) { + LOG(fatal) << "Error: Multiplier values must be non-negative!"; + exit(1); + } else { + LOG(info) << "Multiplier values set to: Pair = " << mult[0] << ", Compton = " << mult[1]; + mMultiplier[0] = mult[0]; + mMultiplier[1] = mult[1]; + } +} + +void GenTPCLoopers::setFlatGas(Bool_t flat, Int_t number, Int_t nloopers_orbit) +{ + mFlatGas = flat; + if (mFlatGas) { + if (nloopers_orbit > 0) { + mFlatGasOrbit = true; + mFlatGasNumber = nloopers_orbit; + LOG(info) << "Flat gas loopers will be generated using orbit reference."; + } else { + mFlatGasOrbit = false; + if (number < 0) { + LOG(warn) << "Warning: Number of loopers per event must be non-negative! Switching option off."; + mFlatGas = false; + mFlatGasNumber = -1; + } else { + mFlatGasNumber = number; + } + } + if (mFlatGas) { + mContextFile = std::filesystem::exists("collisioncontext.root") ? TFile::Open("collisioncontext.root") : nullptr; + mCollisionContext = mContextFile ? (o2::steer::DigitizationContext*)mContextFile->Get("DigitizationContext") : nullptr; + mInteractionTimeRecords = mCollisionContext ? mCollisionContext->getEventRecords() : std::vector{}; + if (mInteractionTimeRecords.empty()) { + LOG(error) << "Error: No interaction time records found in the collision context!"; + exit(1); + } else { + LOG(info) << "Interaction Time records has " << mInteractionTimeRecords.size() << " entries."; + mCollisionContext->printCollisionSummary(); + } + for (int c = 0; c < mInteractionTimeRecords.size() - 1; c++) { + mIntTimeRecMean += mInteractionTimeRecords[c + 1].bc2ns() - mInteractionTimeRecords[c].bc2ns(); + } + mIntTimeRecMean /= (mInteractionTimeRecords.size() - 1); // Average interaction time record used as reference + const auto& hbfUtils = o2::raw::HBFUtils::Instance(); + // Get the start time of the second orbit after the last interaction record + const auto& lastIR = mInteractionTimeRecords.back(); + o2::InteractionRecord finalOrbitIR(0, lastIR.orbit + 2); // Final orbit, BC = 0 + mTimeEnd = finalOrbitIR.bc2ns(); + LOG(debug) << "Final orbit start time: " << mTimeEnd << " ns while last interaction record time is " << mInteractionTimeRecords.back().bc2ns() << " ns"; + } + } else { + mFlatGasNumber = -1; + } + LOG(info) << "Flat gas loopers: " << (mFlatGas ? "ON" : "OFF") << ", Reference loopers number per " << (mFlatGasOrbit ? "orbit " : "event ") << mFlatGasNumber; +} + +void GenTPCLoopers::setFractionPairs(float fractionPairs) +{ + if (fractionPairs < 0 || fractionPairs > 1) { + LOG(fatal) << "Error: Loops fraction for pairs must be in the range [0, 1]."; + exit(1); + } + mLoopsFractionPairs = fractionPairs; + LOG(info) << "Pairs fraction set to: " << mLoopsFractionPairs; +} + +void GenTPCLoopers::SetRate(const std::string& rateFile, bool isPbPb = true, int intRate) +{ + // Checking if the rate file exists and is not empty + TFile rate_file(rateFile.c_str(), "READ"); + if (!rate_file.IsOpen() || rate_file.IsZombie()) { + LOG(fatal) << "Error: Rate file is empty or does not exist!"; + exit(1); + } + const char* fitName = isPbPb ? "fitPbPb" : "fitpp"; + auto fit = (TF1*)rate_file.Get(fitName); + if (!fit) { + LOG(fatal) << "Error: Could not find fit function '" << fitName << "' in rate file!"; + exit(1); + } + mInteractionRate = intRate; + if (mInteractionRate < 0) { + mContextFile = std::filesystem::exists("collisioncontext.root") ? TFile::Open("collisioncontext.root") : nullptr; + if (!mContextFile || mContextFile->IsZombie()) { + LOG(fatal) << "Error: Interaction rate not provided and collision context file not found!"; + exit(1); + } + mCollisionContext = (o2::steer::DigitizationContext*)mContextFile->Get("DigitizationContext"); + mInteractionRate = std::floor(mCollisionContext->getDigitizerInteractionRate()); + LOG(info) << "Interaction rate retrieved from collision context: " << mInteractionRate << " Hz"; + if (mInteractionRate < 0) { + LOG(fatal) << "Error: Invalid interaction rate retrieved from collision context!"; + exit(1); + } + } + auto ref = static_cast(std::floor(fit->Eval(mInteractionRate / 1000.))); // fit expects rate in kHz + rate_file.Close(); + if (ref <= 0) { + LOG(fatal) << "Computed flat gas number reference per orbit is <=0"; + exit(1); + } else { + LOG(info) << "Set flat gas number to " << ref << " loopers per orbit using " << fitName << " from " << mInteractionRate << " Hz interaction rate."; + auto flat = true; + setFlatGas(flat, -1, ref); + } +} + +void GenTPCLoopers::SetAdjust(float adjust) +{ + if (mFlatGas && mFlatGasOrbit && adjust >= -1.f && adjust != 0.f) { + LOG(info) << "Adjusting flat gas number per orbit by " << adjust * 100.f << "%"; + mFlatGasNumber = static_cast(std::round(mFlatGasNumber * (1.f + adjust))); + LOG(info) << "New flat gas number per orbit: " << mFlatGasNumber; + } +} + +} // namespace eventgen +} // namespace o2 \ No newline at end of file diff --git a/Generators/src/TPCLoopersParam.cxx b/Generators/src/TPCLoopersParam.cxx new file mode 100644 index 0000000000000..0202a8ced0535 --- /dev/null +++ b/Generators/src/TPCLoopersParam.cxx @@ -0,0 +1,15 @@ +// Copyright 2024-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author M+Giacalone - September 2025 + +#include "Generators/TPCLoopersParam.h" +O2ParamImpl(o2::eventgen::GenTPCLoopersParam); diff --git a/prodtests/full_system_test.sh b/prodtests/full_system_test.sh index 6408588d46e68..e2ecca590140f 100755 --- a/prodtests/full_system_test.sh +++ b/prodtests/full_system_test.sh @@ -54,8 +54,8 @@ O2SIMSEED=${O2SIMSEED:-0} SPLITTRDDIGI=${SPLITTRDDIGI:-1} DIGITDOWNSCALINGTRD=${DIGITDOWNSCALINGTRD:-1000} NHBPERTF=${NHBPERTF:-128} -RUNFIRSTORBIT=${RUNFIRSTORBIT:-0} -FIRSTSAMPLEDORBIT=${FIRSTSAMPLEDORBIT:-0} +RUNFIRSTORBIT=${RUNFIRSTORBIT:-256} +FIRSTSAMPLEDORBIT=${FIRSTSAMPLEDORBIT:-256} OBLIGATORYSOR=${OBLIGATORYSOR:-false} FST_TPC_ZSVERSION=${FST_TPC_ZSVERSION:-4} TPC_SLOW_REALISITC_FULL_SIM=${TPC_SLOW_REALISITC_FULL_SIM:-0} @@ -137,11 +137,40 @@ if [[ $TPC_SLOW_REALISITC_FULL_SIM == 1 ]]; then DIGITOPTKEY+="TPCEleParam.doCommonModePerPad=0;TPCEleParam.doIonTailPerPad=1;TPCEleParam.commonModeCoupling=0;TPCEleParam.doNoiseEmptyPads=1;TPCEleParam.doSaturationTail=0;TPCDetParam.TPCRecoWindowSim=10;" fi -taskwrapper sim.log o2-sim ${FST_BFIELD+--field=}${FST_BFIELD} --seed $O2SIMSEED -n $NEvents --configKeyValues "\"$SIMOPTKEY\"" -g ${FST_GENERATOR} -e ${FST_MC_ENGINE} -j $NJOBS --run ${RUNNUMBER} -o o2sim +# Create collision context +SIGNALSPEC="o2sim,${FST_COLRATE},1000000:1000000" +QEDSPEC="" +if [[ $FST_QED == 1 ]]; then + PbPbXSec="8." + QEDXSECRATIO=$(awk "BEGIN {printf \"%.2f\",`grep xSectionQED qed/qedgenparam.ini | cut -d'=' -f 2`/$PbPbXSec}") + QEDRATE=$(awk "BEGIN {printf \"%.2f\",${FST_COLRATE}*${QEDXSECRATIO}}") + QEDSPEC="--QEDinteraction qed,${QEDRATE},10000000:${NEventsQED}" +fi + +taskwrapper collcontext.log o2-steer-colcontexttool \ + -i ${SIGNALSPEC} \ + --show-context \ + --timeframeID 0 \ + --orbitsPerTF ${NHBPERTF} \ + --orbits $(( ${NTIMEFRAMES} * ${NHBPERTF} )) \ + --seed ${O2SIMSEED} \ + --noEmptyTF \ + --first-orbit ${RUNFIRSTORBIT} \ + --extract-per-timeframe tf:o2sim \ + --with-vertices kCCDB \ + --maxCollsPerTF ${NEvents} \ + --orbitsEarly 1 \ + --bcPatternFile ccdb \ + ${QEDSPEC} + +# Include collision system for TPC loopers generation +SIMOPTKEY+="GenTPCLoopers.colsys=${BEAMTYPE};" + +taskwrapper sim.log o2-sim ${FST_BFIELD+--field=}${FST_BFIELD} --vertexMode kCollContext --seed $O2SIMSEED -n $NEvents --configKeyValues "\"$SIMOPTKEY\"" -g ${FST_GENERATOR} -e ${FST_MC_ENGINE} -j $NJOBS --run ${RUNNUMBER} -o o2sim --fromCollContext collisioncontext.root:o2sim if [[ $DO_EMBEDDING == 1 ]]; then taskwrapper embed.log o2-sim ${FST_BFIELD+--field=}${FST_BFIELD} -j $NJOBS --run ${RUNNUMBER} -n $NEvents -g pythia8pp -e ${FST_MC_ENGINE} -o sig --configKeyValues ${FST_EMBEDDING_CONFIG} --embedIntoFile o2sim_MCHeader.root fi -taskwrapper digi.log o2-sim-digitizer-workflow -n $NEvents ${DIGIQED} ${NOMCLABELS} --sims ${SIM_SOURCES} --tpc-lanes $((NJOBS < 36 ? NJOBS : 36)) --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} ${DIGITOPT} --configKeyValues "\"${DIGITOPTKEY}\"" --interactionRate $FST_COLRATE --early-forward-policy always +taskwrapper digi.log o2-sim-digitizer-workflow -n $NEvents ${DIGIQED} ${NOMCLABELS} --sims ${SIM_SOURCES} --tpc-lanes $((NJOBS < 36 ? NJOBS : 36)) --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} ${DIGITOPT} --configKeyValues "\"${DIGITOPTKEY}\"" --interactionRate $FST_COLRATE --early-forward-policy always --incontext collisioncontext.root [[ $SPLITTRDDIGI == "1" ]] && taskwrapper digiTRD.log o2-sim-digitizer-workflow -n $NEvents ${NOMCLABELS} --sims ${SIM_SOURCES} --onlyDet TRD --trd-digit-downscaling ${DIGITDOWNSCALINGTRD} --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} --incontext collisioncontext.root --configKeyValues "\"${DIGITOPTKEYTRD}\"" --early-forward-policy always touch digiTRD.log_done From 52b0e23ac5a60f3953749a91a29285b67d7d1558 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 28 Jan 2026 15:32:46 +0100 Subject: [PATCH 122/234] DPL: disable early forwarding for output proxies --- Framework/Core/src/DataProcessingDevice.cxx | 9 +++++++++ Framework/Core/src/ExternalFairMQDeviceProxy.cxx | 2 ++ 2 files changed, 11 insertions(+) diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index 3eaab36fb7908..fd03b7725d847 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -1070,6 +1070,15 @@ void DataProcessingDevice::fillContext(DataProcessorContext& context, DeviceCont break; } } + // Output proxies should wait for the completion policy before forwarding. + // Because they actually do not do anything, that's equivalent to + // forwarding after the processing. + for (auto& label : spec.labels) { + if (label.value == "output-proxy") { + defaultEarlyForwardPolicy = ForwardPolicy::AfterProcessing; + break; + } + } /// We must make sure there is no optional /// if we want to optimize the forwarding diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index b4bfc991db9ae..3b0275879a158 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -1045,6 +1045,7 @@ DataProcessorSpec specifyFairMQDeviceOutputProxy(char const* name, spec.options = { ConfigParamSpec{"channel-config", VariantType::String, d, {"Out-of-band channel config"}}, }; + spec.labels.push_back(DataProcessorLabel{"output-proxy"}); return spec; } @@ -1180,6 +1181,7 @@ DataProcessorSpec specifyFairMQDeviceMultiOutputProxy(char const* name, spec.options = { ConfigParamSpec{"channel-config", VariantType::String, d, {"Out-of-band channel config"}}, }; + spec.labels.push_back(DataProcessorLabel{"output-proxy"}); return spec; } From 3669ad3516f3d4a7ced7685735c35d60a15277f7 Mon Sep 17 00:00:00 2001 From: Felix Weiglhofer Date: Thu, 22 Jan 2026 16:36:03 +0100 Subject: [PATCH 123/234] GPU: Parallelize TPC pad filter over pad rows instead of cachelines. --- GPU/GPUTracking/DataTypes/GPUTPCGeometry.h | 2 + .../Definitions/GPUDefParametersDefaults.h | 8 +- .../Global/GPUChainTrackingClusterizer.cxx | 2 +- .../GPUTPCCFCheckPadBaseline.cxx | 101 +++++++++++++----- .../GPUTPCCFCheckPadBaseline.h | 40 ++++++- 5 files changed, 118 insertions(+), 35 deletions(-) diff --git a/GPU/GPUTracking/DataTypes/GPUTPCGeometry.h b/GPU/GPUTracking/DataTypes/GPUTPCGeometry.h index 9ad83bff363ac..13cec6c752fbe 100644 --- a/GPU/GPUTracking/DataTypes/GPUTPCGeometry.h +++ b/GPU/GPUTracking/DataTypes/GPUTPCGeometry.h @@ -96,6 +96,7 @@ class GPUTPCGeometry // TODO: Make values constexpr GPUd() static constexpr int32_t EndIROC() { return 63; } GPUd() static constexpr int32_t EndOROC1() { return 97; } GPUd() static constexpr int32_t EndOROC2() { return 127; } + GPUd() static constexpr int32_t MaxNPadsPerRow() { return 138; } #else GPUd() static constexpr int32_t GetRegion(int32_t row) { return (row < 63 ? 0 : row < 63 + 64 ? 1 : 2); } GPUd() static constexpr int32_t GetRegionRows(int32_t region) { return 0; } // dummy @@ -104,6 +105,7 @@ class GPUTPCGeometry // TODO: Make values constexpr GPUd() static constexpr int32_t EndIROC() { return 63; } GPUd() static constexpr int32_t EndOROC1() { return 63 + 64; } GPUd() static constexpr int32_t EndOROC2() { return GPUCA_ROW_COUNT; } + GPUd() static constexpr int32_t MaxNPadsPerRow() { return 140; } #endif GPUd() static constexpr float TPCLength() { return 250.f - 0.275f; } diff --git a/GPU/GPUTracking/Definitions/GPUDefParametersDefaults.h b/GPU/GPUTracking/Definitions/GPUDefParametersDefaults.h index 01ae33dc3b4d8..1be881ee6323e 100644 --- a/GPU/GPUTracking/Definitions/GPUDefParametersDefaults.h +++ b/GPU/GPUTracking/Definitions/GPUDefParametersDefaults.h @@ -68,7 +68,7 @@ #define GPUCA_LB_GPUTPCCompressionKernels_step1unattached 512, 2 #define GPUCA_LB_GPUTPCDecompressionKernels_step0attached 128, 2 #define GPUCA_LB_GPUTPCDecompressionKernels_step1unattached 64, 2 - #define GPUCA_LB_GPUTPCCFCheckPadBaseline 64, 10 + #define GPUCA_LB_GPUTPCCFCheckPadBaseline 576, 2 #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillIndexMap 512 #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillFromDigits 512 #define GPUCA_LB_GPUTPCCFChargeMapFiller_findFragmentStart 512 @@ -133,7 +133,7 @@ #define GPUCA_LB_GPUTPCCompressionKernels_step1unattached 512, 2 #define GPUCA_LB_GPUTPCDecompressionKernels_step0attached 128, 2 #define GPUCA_LB_GPUTPCDecompressionKernels_step1unattached 64, 2 - #define GPUCA_LB_GPUTPCCFCheckPadBaseline 64, 2 + #define GPUCA_LB_GPUTPCCFCheckPadBaseline 576, 2 #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillIndexMap 512 #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillFromDigits 512 #define GPUCA_LB_GPUTPCCFChargeMapFiller_findFragmentStart 512 @@ -197,7 +197,7 @@ #define GPUCA_LB_GPUTPCCompressionKernels_step1unattached 512, 3 #define GPUCA_LB_GPUTPCDecompressionKernels_step0attached 32, 1 #define GPUCA_LB_GPUTPCDecompressionKernels_step1unattached 32, 1 - #define GPUCA_LB_GPUTPCCFCheckPadBaseline 64,8 + #define GPUCA_LB_GPUTPCCFCheckPadBaseline 576,2 #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillIndexMap 448 #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillFromDigits 448 #define GPUCA_LB_GPUTPCCFChargeMapFiller_findFragmentStart 448 @@ -447,7 +447,7 @@ #define GPUCA_LB_GPUTPCStartHitsSorter 256 #endif #ifndef GPUCA_LB_GPUTPCCFCheckPadBaseline - #define GPUCA_LB_GPUTPCCFCheckPadBaseline 64 + #define GPUCA_LB_GPUTPCCFCheckPadBaseline 576 #endif #ifndef GPUCA_LB_GPUTPCCFChargeMapFiller_fillIndexMap #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillIndexMap 512 diff --git a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx index 7629086272ed6..bf6577cfd929e 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx @@ -962,7 +962,7 @@ int32_t GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) checkForNoisyPads &= !GetProcessingSettings().disableTPCNoisyPadFilter; if (checkForNoisyPads) { - int32_t nBlocks = TPC_PADS_IN_SECTOR / GPUTPCCFCheckPadBaseline::PadsPerCacheline; + const int32_t nBlocks = GPUTPCCFCheckPadBaseline::GetNBlocks(doGPU); runKernel({GetGridBlk(nBlocks, lane), {iSector}}); getKernelTimer(RecoStep::TPCClusterFinding, iSector, TPC_PADS_IN_SECTOR * fragment.lengthWithoutOverlap() * sizeof(PackedCharge), false); diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.cxx index 3248e517ff465..33ed089890bc4 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.cxx @@ -9,13 +9,12 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file GPUTPCCFCheckPadBaseline.h +/// \file GPUTPCCFCheckPadBaseline.cxx /// \author Felix Weiglhofer #include "GPUTPCCFCheckPadBaseline.h" #include "CfArray2D.h" #include "PackedCharge.h" -#include "GPUTPCGeometry.h" #include "clusterFinderDefs.h" #ifndef GPUCA_GPUCODE @@ -28,51 +27,88 @@ using namespace o2::gpu::tpccf; template <> GPUd() void GPUTPCCFCheckPadBaseline::Thread<0>(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer) { - const CfFragment& fragment = clusterer.mPmemory->fragment; - CfArray2D chargeMap(reinterpret_cast(clusterer.mPchargeMap)); - - int32_t basePad = iBlock * PadsPerCacheline; - CfChargePos basePos = padToCfChargePos(basePad, clusterer); +#ifdef GPUCA_GPUCODE + CheckBaselineGPU(nBlocks, nThreads, iBlock, iThread, smem, clusterer); +#else + CheckBaselineCPU(nBlocks, nThreads, iBlock, iThread, smem, clusterer); +#endif +} - if (not basePos.valid()) { +// Charges are stored in a 2D array (pad and time) using a tiling layout. +// Tiles are 8 pads x 4 timebins large stored in time-major layout and make up a single cacheline. +// +// This kernel processes one row per block. Threads cooperatively load chunks +// of 4 consecutive time bins for all pads into shared memory. Thread `i` then processes charges for pad `i` in shared memory. +// Blocks require `nextMultipleOf<64>(138 * 4) = 576` threads to process the largest TPC rows with 138 pads correctly. +GPUd() void GPUTPCCFCheckPadBaseline::CheckBaselineGPU(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer) +{ +#ifdef GPUCA_GPUCODE + if (iBlock >= GPUCA_ROW_COUNT) { return; } -#ifdef GPUCA_GPUCODE - static_assert(TPC_MAX_FRAGMENT_LEN_GPU % NumOfCachedTimebins == 0); + const CfFragment& fragment = clusterer.mPmemory->fragment; + CfArray2D chargeMap(reinterpret_cast(clusterer.mPchargeMap)); + + const auto iRow = iBlock; + const auto rowinfo = GetRowInfo(iRow); + const CfChargePos basePos{(Row)iRow, 0, 0}; int32_t totalCharges = 0; int32_t consecCharges = 0; int32_t maxConsecCharges = 0; Charge maxCharge = 0; - int16_t localPadId = iThread / NumOfCachedTimebins; - int16_t localTimeBin = iThread % NumOfCachedTimebins; - bool handlePad = localTimeBin == 0; + const int16_t iPadOffset = iThread % MaxNPadsPerRow; + const int16_t iTimeOffset = iThread / MaxNPadsPerRow; + const int16_t iPadHandle = iThread; + const bool handlePad = iPadHandle < rowinfo.nPads; + + const auto firstTB = fragment.firstNonOverlapTimeBin(); + const auto lastTB = fragment.lastNonOverlapTimeBin(); + + for (auto t = firstTB; t < lastTB; t += NumOfCachedTBs) { + + const TPCFragmentTime iTime = t + iTimeOffset; + + const CfChargePos pos = basePos.delta({iPadOffset, iTime}); + + smem.charges[iTimeOffset][iPadOffset] = iTime < lastTB && iPadOffset < rowinfo.nPads ? chargeMap[pos].unpack() : 0; - for (tpccf::TPCFragmentTime t = fragment.firstNonOverlapTimeBin(); t < fragment.lastNonOverlapTimeBin(); t += NumOfCachedTimebins) { - const CfChargePos pos = basePos.delta({localPadId, int16_t(t + localTimeBin)}); - smem.charges[localPadId][localTimeBin] = (pos.valid()) ? chargeMap[pos].unpack() : 0; GPUbarrier(); + if (handlePad) { - for (int32_t i = 0; i < NumOfCachedTimebins; i++) { - const Charge q = smem.charges[localPadId][i]; + for (int32_t i = 0; i < NumOfCachedTBs; i++) { + const Charge q = smem.charges[i][iPadHandle]; totalCharges += (q > 0); consecCharges = (q > 0) ? consecCharges + 1 : 0; maxConsecCharges = CAMath::Max(consecCharges, maxConsecCharges); maxCharge = CAMath::Max(q, maxCharge); } } + GPUbarrier(); } - GPUbarrier(); - if (handlePad) { - updatePadBaseline(basePad + localPadId, clusterer, totalCharges, maxConsecCharges, maxCharge); + updatePadBaseline(rowinfo.globalPadOffset + iPadOffset, clusterer, totalCharges, maxConsecCharges, maxCharge); } +#endif +} -#else // CPU CODE +GPUd() void GPUTPCCFCheckPadBaseline::CheckBaselineCPU(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer) +{ +#ifndef GPUCA_GPUCODE + const CfFragment& fragment = clusterer.mPmemory->fragment; + CfArray2D chargeMap(reinterpret_cast(clusterer.mPchargeMap)); + + int32_t basePad = iBlock * PadsPerCacheline; + int32_t padsPerRow; + CfChargePos basePos = padToCfChargePos(basePad, clusterer, padsPerRow); + + if (not basePos.valid()) { + return; + } constexpr size_t ElemsInTileRow = (size_t)TilingLayout>::WidthInTiles * TimebinsPerCacheline * PadsPerCacheline; @@ -122,7 +158,8 @@ GPUd() void GPUTPCCFCheckPadBaseline::Thread<0>(int32_t nBlocks, int32_t nThread #endif } -GPUd() CfChargePos GPUTPCCFCheckPadBaseline::padToCfChargePos(int32_t& pad, const GPUTPCClusterFinder& clusterer) +template +GPUd() CfChargePos GPUTPCCFCheckPadBaseline::padToCfChargePos(int32_t& pad, const GPUTPCClusterFinder& clusterer, int32_t& padsPerRow) { constexpr GPUTPCGeometry geo; @@ -130,17 +167,31 @@ GPUd() CfChargePos GPUTPCCFCheckPadBaseline::padToCfChargePos(int32_t& pad, cons for (Row r = 0; r < GPUCA_ROW_COUNT; r++) { int32_t npads = geo.NPads(r); int32_t padInRow = pad - padOffset; - if (0 <= padInRow && padInRow < CAMath::nextMultipleOf(npads)) { - int32_t cachelineOffset = padInRow % PadsPerCacheline; + if (0 <= padInRow && padInRow < npads) { + int32_t cachelineOffset = padInRow % PadsPerBlock; pad -= cachelineOffset; + padsPerRow = npads; return CfChargePos{r, Pad(padInRow - cachelineOffset), 0}; } padOffset += npads; } + padsPerRow = 0; return CfChargePos{0, 0, INVALID_TIME_BIN}; } +GPUd() GPUTPCCFCheckPadBaseline::RowInfo GPUTPCCFCheckPadBaseline::GetRowInfo(int16_t row) +{ + constexpr GPUTPCGeometry geo; + + int16_t padOffset = 0; + for (int16_t r = 0; r < row; r++) { + padOffset += geo.NPads(r); + } + + return RowInfo{padOffset, geo.NPads(row)}; +} + GPUd() void GPUTPCCFCheckPadBaseline::updatePadBaseline(int32_t pad, const GPUTPCClusterFinder& clusterer, int32_t totalCharges, int32_t consecCharges, Charge maxCharge) { const CfFragment& fragment = clusterer.mPmemory->fragment; diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.h index 25c93a4649662..a71f1358a73a6 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.h @@ -11,14 +11,20 @@ /// \file GPUTPCCFCheckPadBaseline.h /// \author Felix Weiglhofer +/// +/// Kernel identifies noisy TPC pads by analyzing charge patterns over time. +/// A pad is marked noisy if it exceeds thresholds for total or consecutive +/// time bins with charge, unless the charge exceeds a saturation threshold. #ifndef O2_GPU_GPU_TPC_CF_CHECK_PAD_BASELINE_H #define O2_GPU_GPU_TPC_CF_CHECK_PAD_BASELINE_H #include "GPUGeneralKernels.h" #include "GPUConstantMem.h" +#include "GPUTPCGeometry.h" #include "clusterFinderDefs.h" +#include "CfArray2D.h" namespace o2::gpu { @@ -28,13 +34,20 @@ class GPUTPCCFCheckPadBaseline : public GPUKernelTemplate public: enum { - PadsPerCacheline = 8, - TimebinsPerCacheline = 4, - NumOfCachedTimebins = GPUCA_GET_THREAD_COUNT(GPUCA_LB_GPUTPCCFCheckPadBaseline) / PadsPerCacheline, + PadsPerCacheline = TPCMapMemoryLayout::Width, + TimebinsPerCacheline = TPCMapMemoryLayout::Height, + EntriesPerCacheline = PadsPerCacheline * TimebinsPerCacheline, + NumOfCachedPads = GPUCA_WARP_SIZE / TimebinsPerCacheline, + NumCLsPerWarp = GPUCA_WARP_SIZE / EntriesPerCacheline, + NumOfCachedTBs = TimebinsPerCacheline, + // Threads index shared memory as [iThread / MaxNPadsPerRow][iThread % MaxNPadsPerRow]. + // Rounding up to a multiple of PadsPerCacheline ensures iThread / MaxNPadsPerRow < NumOfCachedTBs + // for all threads, avoiding out-of-bounds access. + MaxNPadsPerRow = CAMath::nextMultipleOf(GPUTPCGeometry::MaxNPadsPerRow()), }; struct GPUSharedMemory { - tpccf::Charge charges[PadsPerCacheline][NumOfCachedTimebins]; + tpccf::Charge charges[NumOfCachedTBs][MaxNPadsPerRow]; }; typedef GPUTPCClusterFinder processorType; @@ -48,11 +61,28 @@ class GPUTPCCFCheckPadBaseline : public GPUKernelTemplate return gpudatatypes::RecoStep::TPCClusterFinding; } + static int32_t GetNBlocks(bool isGPU) + { + const int32_t nBlocks = TPC_PADS_IN_SECTOR / PadsPerCacheline; + return isGPU ? GPUCA_ROW_COUNT : nBlocks; + } + template GPUd() static void Thread(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer); private: - GPUd() static CfChargePos padToCfChargePos(int32_t& pad, const GPUTPCClusterFinder&); + GPUd() static void CheckBaselineGPU(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer); + GPUd() static void CheckBaselineCPU(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, GPUSharedMemory& smem, processorType& clusterer); + + template + GPUd() static CfChargePos padToCfChargePos(int32_t& pad, const GPUTPCClusterFinder&, int32_t& padsPerRow); + + struct RowInfo { + int16_t globalPadOffset; + int16_t nPads; + }; + GPUd() static RowInfo GetRowInfo(int16_t row); + GPUd() static void updatePadBaseline(int32_t pad, const GPUTPCClusterFinder&, int32_t totalCharges, int32_t consecCharges, tpccf::Charge maxCharge); }; From f86363afb697abe64b9bf593a6cd92dd45b49aae Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Mon, 26 Jan 2026 13:16:00 +0100 Subject: [PATCH 124/234] ITS: instaniate TRK classes Signed-off-by: Felix Schlepper --- Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx | 4 ++++ Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx | 13 +++++++++++-- Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx | 4 ++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx b/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx index 0d8b461181741..70f4e3d1d3fc7 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx @@ -667,5 +667,9 @@ void TimeFrame::wipe() } template class TimeFrame<7>; +// ALICE3 upgrade +#ifdef ENABLE_UPGRADES +template class TimeFrame<11>; +#endif } // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx b/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx index 59459dcab17e8..658a90b37613f 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx @@ -145,8 +145,13 @@ void Tracker::clustersToTracks(const LogFunc& logger, const LogFunc& er } catch (const std::bad_alloc& err) { handleException(err); return; - } catch (...) { - error("Uncaught exception, all bets are off..."); + } catch (const std::exception& err) { + error(std::format("Uncaught exception, all bets are off... {}", err.what())); + // clear tracks explicitly since if not fatalising on exception this may contain partial output + for (int iROF{0}; iROF < mTimeFrame->getNrof(); ++iROF) { + mTimeFrame->getTracks(iROF).clear(); + } + return; } if (mTimeFrame->hasMCinformation()) { @@ -357,5 +362,9 @@ void Tracker::printSummary() const } template class Tracker<7>; +// ALICE3 upgrade +#ifdef ENABLE_UPGRADES +template class Tracker<11>; +#endif } // namespace o2::its diff --git a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx index fe67eadaf6f72..15459576a1031 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx @@ -1327,5 +1327,9 @@ void TrackerTraits::setNThreads(int n, std::shared_ptr } template class TrackerTraits<7>; +// ALICE3 upgrade +#ifdef ENABLE_UPGRADES +template class TrackerTraits<11>; +#endif } // namespace o2::its From 2d37a89a8539690def207cc7fd55dbf8b7514b03 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Mon, 26 Jan 2026 13:53:46 +0100 Subject: [PATCH 125/234] ITS: enlarge StartLayerMask for TRK Signed-off-by: Felix Schlepper --- .../ITSMFT/ITS/tracking/include/ITStracking/Configuration.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h index 1019a3e3d45a9..1c4d604a629ed 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h @@ -68,7 +68,7 @@ struct TrackingParameters { float MaxChi2NDF = 30.f; int ReseedIfShorter = 6; // reseed for the final fit track with the length shorter than this std::vector MinPt = {0.f, 0.f, 0.f, 0.f}; - unsigned char StartLayerMask = 0x7F; + uint16_t StartLayerMask = 0x7F; bool RepeatRefitOut = true; // repeat outward refit using inward refit as a seed bool ShiftRefToCluster = true; // TrackFit: after update shift the linearization reference to cluster bool FindShortTracks = false; From 8eebfb5e616c670e42b7a41742b64c123a9e7b54 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Mon, 26 Jan 2026 17:30:26 +0100 Subject: [PATCH 126/234] ITS: GPU: reduce TrackITS allocation Signed-off-by: Felix Schlepper --- .../GPU/ITStrackingGPU/TimeFrameGPU.h | 8 +- .../GPU/ITStrackingGPU/TrackingKernels.h | 61 +++++-- .../ITS/tracking/GPU/cuda/TimeFrameGPU.cu | 23 +-- .../tracking/GPU/cuda/TrackerTraitsGPU.cxx | 65 ++++--- .../ITS/tracking/GPU/cuda/TrackingKernels.cu | 169 +++++++++++++----- 5 files changed, 234 insertions(+), 92 deletions(-) diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameGPU.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameGPU.h index 8095d690bbcc8..d6d87eb8c1143 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameGPU.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameGPU.h @@ -80,8 +80,8 @@ class TimeFrameGPU final : public TimeFrame void createNeighboursIndexTablesDevice(const int); void createNeighboursDevice(const unsigned int layer); void createNeighboursLUTDevice(const int, const unsigned int); - void createTrackITSExtDevice(bounded_vector&); - void downloadTrackITSExtDevice(bounded_vector&); + void createTrackITSExtDevice(const size_t); + void downloadTrackITSExtDevice(); void downloadCellsNeighboursDevice(std::vector>>&, const int); void downloadNeighboursLUTDevice(bounded_vector&, const int); void downloadCellsDevice(); @@ -140,6 +140,8 @@ class TimeFrameGPU final : public TimeFrame int** getDeviceArrayNeighboursCellLUT() const { return mNeighboursCellLUTDeviceArray; } CellSeedN** getDeviceArrayCells() { return mCellsDeviceArray; } CellSeedN* getDeviceTrackSeeds() { return mTrackSeedsDevice; } + int* getDeviceTrackSeedsLUT() { return mTrackSeedsLUTDevice; } + auto getNTrackSeeds() const { return mNTracks; } o2::track::TrackParCovF** getDeviceArrayTrackSeeds() { return mCellSeedsDeviceArray; } float** getDeviceArrayTrackSeedsChi2() { return mCellSeedsChi2DeviceArray; } int* getDeviceNeighboursIndexTables(const int layer) { return mNeighboursIndexTablesDevice[layer]; } @@ -219,6 +221,8 @@ class TimeFrameGPU final : public TimeFrame CellSeedN** mCellsDeviceArray; std::array mNeighboursIndexTablesDevice; CellSeedN* mTrackSeedsDevice{nullptr}; + int* mTrackSeedsLUTDevice{nullptr}; + unsigned int mNTracks{0}; std::array mCellSeedsDevice; o2::track::TrackParCovF** mCellSeedsDeviceArray; std::array mCellSeedsChi2Device; diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h index 6e0427f5413ba..53992ccf3eb85 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h @@ -207,23 +207,48 @@ void processNeighboursHandler(const int startLayer, const int nThreads); template -void trackSeedHandler(CellSeed* trackSeeds, - const TrackingFrameInfo** foundTrackingFrameInfo, - const Cluster** unsortedClusters, - o2::its::TrackITSExt* tracks, - const std::vector& layerRadiiHost, - const std::vector& minPtsHost, - const unsigned int nSeeds, - const float Bz, - const int startLevel, - const float maxChi2ClusterAttachment, - const float maxChi2NDF, - const int reseedIfShorter, - const bool repeatRefitOut, - const bool shiftRefToCluster, - const o2::base::Propagator* propagator, - const o2::base::PropagatorF::MatCorrType matCorrType, - const int nBlocks, - const int nThreads); +void countTrackSeedHandler(CellSeed* trackSeeds, + const TrackingFrameInfo** foundTrackingFrameInfo, + const Cluster** unsortedClusters, + int* seedLUT, + const std::vector& layerRadiiHost, + const std::vector& minPtsHost, + const unsigned int nSeeds, + const float Bz, + const int startLevel, + const float maxChi2ClusterAttachment, + const float maxChi2NDF, + const int reseedIfShorter, + const bool repeatRefitOut, + const bool shiftRefToCluster, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType, + o2::its::ExternalAllocator* alloc, + const int nBlocks, + const int nThreads); + +template +void computeTrackSeedHandler(CellSeed* trackSeeds, + const TrackingFrameInfo** foundTrackingFrameInfo, + const Cluster** unsortedClusters, + o2::its::TrackITSExt* tracks, + const int* seedLUT, + const std::vector& layerRadiiHost, + const std::vector& minPtsHost, + const unsigned int nSeeds, + const unsigned int nTracks, + const float Bz, + const int startLevel, + const float maxChi2ClusterAttachment, + const float maxChi2NDF, + const int reseedIfShorter, + const bool repeatRefitOut, + const bool shiftRefToCluster, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType, + o2::its::ExternalAllocator* alloc, + const int nBlocks, + const int nThreads); + } // namespace o2::its #endif // ITSTRACKINGGPU_TRACKINGKERNELS_H_ diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu index 6532165d9628a..c7d6e31ec771a 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu @@ -439,8 +439,10 @@ void TimeFrameGPU::loadTrackSeedsDevice(bounded_vector& seed GPUTimer timer("loading track seeds"); GPULog("gpu-transfer: loading {} track seeds, for {:.2f} MB.", seeds.size(), seeds.size() * sizeof(CellSeedN) / constants::MB); allocMem(reinterpret_cast(&mTrackSeedsDevice), seeds.size() * sizeof(CellSeedN), this->hasFrameworkAllocator(), (o2::gpu::GPUMemoryResource::MEMORY_GPU | o2::gpu::GPUMemoryResource::MEMORY_STACK)); - GPUChkErrS(cudaHostRegister(seeds.data(), seeds.size() * sizeof(CellSeedN), cudaHostRegisterPortable)); GPUChkErrS(cudaMemcpy(mTrackSeedsDevice, seeds.data(), seeds.size() * sizeof(CellSeedN), cudaMemcpyHostToDevice)); + GPULog("gpu-transfer: creating {} track seeds LUT, for {:.2f} MB.", seeds.size() + 1, (seeds.size() + 1) * sizeof(int) / constants::MB); + allocMem(reinterpret_cast(&mTrackSeedsLUTDevice), (seeds.size() + 1) * sizeof(int), this->hasFrameworkAllocator(), (o2::gpu::GPUMemoryResource::MEMORY_GPU | o2::gpu::GPUMemoryResource::MEMORY_STACK)); + GPUChkErrS(cudaMemset(mTrackSeedsLUTDevice, 0, (seeds.size() + 1) * sizeof(int))); } template @@ -458,14 +460,15 @@ void TimeFrameGPU::createNeighboursDevice(const unsigned int layer) } template -void TimeFrameGPU::createTrackITSExtDevice(bounded_vector& seeds) +void TimeFrameGPU::createTrackITSExtDevice(const size_t nSeeds) { GPUTimer timer("reserving tracks"); - mTrackITSExt = bounded_vector(seeds.size(), {}, this->getMemoryPool().get()); - GPULog("gpu-allocation: reserving {} tracks, for {:.2f} MB.", seeds.size(), seeds.size() * sizeof(o2::its::TrackITSExt) / constants::MB); - allocMem(reinterpret_cast(&mTrackITSExtDevice), seeds.size() * sizeof(o2::its::TrackITSExt), this->hasFrameworkAllocator(), (o2::gpu::GPUMemoryResource::MEMORY_GPU | o2::gpu::GPUMemoryResource::MEMORY_STACK)); - GPUChkErrS(cudaMemset(mTrackITSExtDevice, 0, seeds.size() * sizeof(o2::its::TrackITSExt))); - GPUChkErrS(cudaHostRegister(mTrackITSExt.data(), seeds.size() * sizeof(o2::its::TrackITSExt), cudaHostRegisterPortable)); + mNTracks = 0; + GPUChkErrS(cudaMemcpy(&mNTracks, mTrackSeedsLUTDevice + nSeeds, sizeof(int), cudaMemcpyDeviceToHost)); + GPULog("gpu-allocation: reserving {} tracks, for {:.2f} MB.", mNTracks, mNTracks * sizeof(o2::its::TrackITSExt) / constants::MB); + mTrackITSExt = bounded_vector(mNTracks, {}, this->getMemoryPool().get()); + allocMem(reinterpret_cast(&mTrackITSExtDevice), mNTracks * sizeof(o2::its::TrackITSExt), this->hasFrameworkAllocator(), (o2::gpu::GPUMemoryResource::MEMORY_GPU | o2::gpu::GPUMemoryResource::MEMORY_STACK)); + GPUChkErrS(cudaMemset(mTrackITSExtDevice, 0, mNTracks * sizeof(o2::its::TrackITSExt))); } template @@ -588,13 +591,11 @@ void TimeFrameGPU::downloadNeighboursLUTDevice(bounded_vector& lut } template -void TimeFrameGPU::downloadTrackITSExtDevice(bounded_vector& seeds) +void TimeFrameGPU::downloadTrackITSExtDevice() { GPUTimer timer("downloading tracks"); GPULog("gpu-transfer: downloading {} tracks, for {:.2f} MB.", mTrackITSExt.size(), mTrackITSExt.size() * sizeof(o2::its::TrackITSExt) / constants::MB); - GPUChkErrS(cudaMemcpy(mTrackITSExt.data(), mTrackITSExtDevice, seeds.size() * sizeof(o2::its::TrackITSExt), cudaMemcpyDeviceToHost)); - GPUChkErrS(cudaHostUnregister(mTrackITSExt.data())); - GPUChkErrS(cudaHostUnregister(seeds.data())); + GPUChkErrS(cudaMemcpy(mTrackITSExt.data(), mTrackITSExtDevice, mTrackITSExt.size() * sizeof(o2::its::TrackITSExt), cudaMemcpyDeviceToHost)); } template diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx index c4a5cfb4e26b3..60774e3313d7f 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx @@ -322,29 +322,52 @@ void TrackerTraitsGPU::findRoads(const int iteration) LOGP(debug, "No track seeds found, skipping track finding"); continue; } - mTimeFrameGPU->createTrackITSExtDevice(trackSeeds); mTimeFrameGPU->loadTrackSeedsDevice(trackSeeds); - trackSeedHandler(mTimeFrameGPU->getDeviceTrackSeeds(), // CellSeed* - mTimeFrameGPU->getDeviceArrayTrackingFrameInfo(), // TrackingFrameInfo** - mTimeFrameGPU->getDeviceArrayUnsortedClusters(), // Cluster** - mTimeFrameGPU->getDeviceTrackITSExt(), // o2::its::TrackITSExt* - this->mTrkParams[iteration].LayerRadii, // const std::vector& - this->mTrkParams[iteration].MinPt, // const std::vector& - trackSeeds.size(), // const size_t nSeeds - this->mBz, // const float Bz - startLevel, // const int startLevel, - this->mTrkParams[0].MaxChi2ClusterAttachment, // float maxChi2ClusterAttachment - this->mTrkParams[0].MaxChi2NDF, // float maxChi2NDF - this->mTrkParams[0].RepeatRefitOut, - this->mTrkParams[0].ReseedIfShorter, - this->mTrkParams[0].ShiftRefToCluster, - mTimeFrameGPU->getDevicePropagator(), // const o2::base::Propagator* propagator - this->mTrkParams[0].CorrType, // o2::base::PropagatorImpl::MatCorrType - conf.nBlocksTracksSeeds[iteration], - conf.nThreadsTracksSeeds[iteration]); - - mTimeFrameGPU->downloadTrackITSExtDevice(trackSeeds); + // Since TrackITSExt is an enourmous class it is better to first count how many + // successfull fits we do and only then allocate + countTrackSeedHandler(mTimeFrameGPU->getDeviceTrackSeeds(), + mTimeFrameGPU->getDeviceArrayTrackingFrameInfo(), + mTimeFrameGPU->getDeviceArrayUnsortedClusters(), + mTimeFrameGPU->getDeviceTrackSeedsLUT(), + this->mTrkParams[iteration].LayerRadii, + this->mTrkParams[iteration].MinPt, + trackSeeds.size(), + this->mBz, + startLevel, + this->mTrkParams[0].MaxChi2ClusterAttachment, + this->mTrkParams[0].MaxChi2NDF, + this->mTrkParams[0].RepeatRefitOut, + this->mTrkParams[0].ReseedIfShorter, + this->mTrkParams[0].ShiftRefToCluster, + mTimeFrameGPU->getDevicePropagator(), + this->mTrkParams[0].CorrType, + mTimeFrameGPU->getFrameworkAllocator(), + conf.nBlocksTracksSeeds[iteration], + conf.nThreadsTracksSeeds[iteration]); + mTimeFrameGPU->createTrackITSExtDevice(trackSeeds.size()); + computeTrackSeedHandler(mTimeFrameGPU->getDeviceTrackSeeds(), + mTimeFrameGPU->getDeviceArrayTrackingFrameInfo(), + mTimeFrameGPU->getDeviceArrayUnsortedClusters(), + mTimeFrameGPU->getDeviceTrackITSExt(), + mTimeFrameGPU->getDeviceTrackSeedsLUT(), + this->mTrkParams[iteration].LayerRadii, + this->mTrkParams[iteration].MinPt, + trackSeeds.size(), + mTimeFrameGPU->getNTrackSeeds(), + this->mBz, + startLevel, + this->mTrkParams[0].MaxChi2ClusterAttachment, + this->mTrkParams[0].MaxChi2NDF, + this->mTrkParams[0].RepeatRefitOut, + this->mTrkParams[0].ReseedIfShorter, + this->mTrkParams[0].ShiftRefToCluster, + mTimeFrameGPU->getDevicePropagator(), + this->mTrkParams[0].CorrType, + mTimeFrameGPU->getFrameworkAllocator(), + conf.nBlocksTracksSeeds[iteration], + conf.nThreadsTracksSeeds[iteration]); + mTimeFrameGPU->downloadTrackITSExtDevice(); auto& tracks = mTimeFrameGPU->getTrackITSExt(); diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu index 85689488f5f6e..e5427c07cb52b 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu @@ -277,12 +277,13 @@ struct compare_track_chi2 { } }; -template +template GPUg() void __launch_bounds__(256, 1) fitTrackSeedsKernel( CellSeed* trackSeeds, const TrackingFrameInfo** foundTrackingFrameInfo, const Cluster** unsortedClusters, o2::its::TrackITSExt* tracks, + maybe_const* seedLUT, const float* layerRadii, const float* minPts, const unsigned int nSeeds, @@ -297,6 +298,13 @@ GPUg() void __launch_bounds__(256, 1) fitTrackSeedsKernel( const o2::base::PropagatorF::MatCorrType matCorrType) { for (int iCurrentTrackSeedIndex = blockIdx.x * blockDim.x + threadIdx.x; iCurrentTrackSeedIndex < nSeeds; iCurrentTrackSeedIndex += blockDim.x * gridDim.x) { + + if constexpr (!initRun) { + if (seedLUT[iCurrentTrackSeedIndex] == seedLUT[iCurrentTrackSeedIndex + 1]) { + continue; + } + } + TrackITSExt temporaryTrack = seedTrackForRefit(trackSeeds[iCurrentTrackSeedIndex], foundTrackingFrameInfo, unsortedClusters, layerRadii, bz, reseedIfShorter); o2::track::TrackPar linRef{temporaryTrack}; bool fitSuccess = fitTrack(temporaryTrack, // TrackITSExt& track, @@ -366,7 +374,12 @@ GPUg() void __launch_bounds__(256, 1) fitTrackSeedsKernel( temporaryTrack.getParamIn() = saveInw; temporaryTrack.setChi2(saveChi2); } - tracks[iCurrentTrackSeedIndex] = temporaryTrack; + + if constexpr (initRun) { + seedLUT[iCurrentTrackSeedIndex] = 1; + } else { + tracks[seedLUT[iCurrentTrackSeedIndex]] = temporaryTrack; + } } } @@ -1191,32 +1204,84 @@ void processNeighboursHandler(const int startLayer, } template -void trackSeedHandler(CellSeed* trackSeeds, - const TrackingFrameInfo** foundTrackingFrameInfo, - const Cluster** unsortedClusters, - o2::its::TrackITSExt* tracks, - const std::vector& layerRadiiHost, - const std::vector& minPtsHost, - const unsigned int nSeeds, - const float bz, - const int startLevel, - const float maxChi2ClusterAttachment, - const float maxChi2NDF, - const int reseedIfShorter, - const bool repeatRefitOut, - const bool shiftRefToCluster, - const o2::base::Propagator* propagator, - const o2::base::PropagatorF::MatCorrType matCorrType, - const int nBlocks, - const int nThreads) +void countTrackSeedHandler(CellSeed* trackSeeds, + const TrackingFrameInfo** foundTrackingFrameInfo, + const Cluster** unsortedClusters, + int* seedLUT, + const std::vector& layerRadiiHost, + const std::vector& minPtsHost, + const unsigned int nSeeds, + const float bz, + const int startLevel, + const float maxChi2ClusterAttachment, + const float maxChi2NDF, + const int reseedIfShorter, + const bool repeatRefitOut, + const bool shiftRefToCluster, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType, + o2::its::ExternalAllocator* alloc, + const int nBlocks, + const int nThreads) +{ + // TODO: the minPts&layerRadii is transfered twice + // we should allocate this in constant memory and stop these + // small transferes! + thrust::device_vector minPts(minPtsHost); + thrust::device_vector layerRadii(layerRadiiHost); + gpu::fitTrackSeedsKernel<<>>( + trackSeeds, // CellSeed* + foundTrackingFrameInfo, // TrackingFrameInfo** + unsortedClusters, // Cluster** + nullptr, // TrackITSExt* + seedLUT, // int* + thrust::raw_pointer_cast(&layerRadii[0]), // const float* + thrust::raw_pointer_cast(&minPts[0]), // const float* + nSeeds, // const unsigned int + bz, // const float + startLevel, // const int + maxChi2ClusterAttachment, // float + maxChi2NDF, // float + reseedIfShorter, // int + repeatRefitOut, // bool + shiftRefToCluster, // bool + propagator, // const o2::base::Propagator* + matCorrType); // o2::base::PropagatorF::MatCorrType + auto sync_policy = THRUST_NAMESPACE::par(gpu::TypedAllocator(alloc)); + thrust::exclusive_scan(sync_policy, seedLUT, seedLUT + nSeeds + 1, seedLUT); +} + +template +void computeTrackSeedHandler(CellSeed* trackSeeds, + const TrackingFrameInfo** foundTrackingFrameInfo, + const Cluster** unsortedClusters, + o2::its::TrackITSExt* tracks, + const int* seedLUT, + const std::vector& layerRadiiHost, + const std::vector& minPtsHost, + const unsigned int nSeeds, + const unsigned int nTracks, + const float bz, + const int startLevel, + const float maxChi2ClusterAttachment, + const float maxChi2NDF, + const int reseedIfShorter, + const bool repeatRefitOut, + const bool shiftRefToCluster, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType, + o2::its::ExternalAllocator* alloc, + const int nBlocks, + const int nThreads) { thrust::device_vector minPts(minPtsHost); thrust::device_vector layerRadii(layerRadiiHost); - gpu::fitTrackSeedsKernel<<>>( + gpu::fitTrackSeedsKernel<<>>( trackSeeds, // CellSeed* foundTrackingFrameInfo, // TrackingFrameInfo** unsortedClusters, // Cluster** tracks, // TrackITSExt* + seedLUT, // const int* thrust::raw_pointer_cast(&layerRadii[0]), // const float* thrust::raw_pointer_cast(&minPts[0]), // const float* nSeeds, // const unsigned int @@ -1229,8 +1294,9 @@ void trackSeedHandler(CellSeed* trackSeeds, shiftRefToCluster, // bool propagator, // const o2::base::Propagator* matCorrType); // o2::base::PropagatorF::MatCorrType + auto sync_policy = THRUST_NAMESPACE::par(gpu::TypedAllocator(alloc)); thrust::device_ptr tr_ptr(tracks); - thrust::sort(tr_ptr, tr_ptr + nSeeds, gpu::compare_track_chi2()); + thrust::sort(sync_policy, tr_ptr, tr_ptr + nTracks, gpu::compare_track_chi2()); } /// Explicit instantiation of ITS2 handlers @@ -1394,23 +1460,46 @@ template void processNeighboursHandler<7>(const int startLayer, const int nBlocks, const int nThreads); -template void trackSeedHandler(CellSeed<7>* trackSeeds, - const TrackingFrameInfo** foundTrackingFrameInfo, - const Cluster** unsortedClusters, - o2::its::TrackITSExt* tracks, - const std::vector& layerRadiiHost, - const std::vector& minPtsHost, - const unsigned int nSeeds, - const float bz, - const int startLevel, - const float maxChi2ClusterAttachment, - const float maxChi2NDF, - const int reseedIfShorter, - const bool repeatRefitOut, - const bool shiftRefToCluster, - const o2::base::Propagator* propagator, - const o2::base::PropagatorF::MatCorrType matCorrType, - const int nBlocks, - const int nThreads); +template void countTrackSeedHandler(CellSeed<7>* trackSeeds, + const TrackingFrameInfo** foundTrackingFrameInfo, + const Cluster** unsortedClusters, + int* seedLUT, + const std::vector& layerRadiiHost, + const std::vector& minPtsHost, + const unsigned int nSeeds, + const float bz, + const int startLevel, + const float maxChi2ClusterAttachment, + const float maxChi2NDF, + const int reseedIfShorter, + const bool repeatRefitOut, + const bool shiftRefToCluster, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType, + o2::its::ExternalAllocator* alloc, + const int nBlocks, + const int nThreads); + +template void computeTrackSeedHandler(CellSeed<7>* trackSeeds, + const TrackingFrameInfo** foundTrackingFrameInfo, + const Cluster** unsortedClusters, + o2::its::TrackITSExt* tracks, + const int* seedLUT, + const std::vector& layerRadiiHost, + const std::vector& minPtsHost, + const unsigned int nSeeds, + const unsigned int nTracks, + const float bz, + const int startLevel, + const float maxChi2ClusterAttachment, + const float maxChi2NDF, + const int reseedIfShorter, + const bool repeatRefitOut, + const bool shiftRefToCluster, + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType, + o2::its::ExternalAllocator* alloc, + const int nBlocks, + const int nThreads); } // namespace o2::its From c3f85c1d7cbbd4c9e16819f1f0d23b47d7004796 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Mon, 26 Jan 2026 17:31:50 +0100 Subject: [PATCH 127/234] ITS: fix correctForMaterial arg for actual layer Signed-off-by: Felix Schlepper --- Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu | 2 +- Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu index e5427c07cb52b..7c257bc1d0ba1 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu @@ -505,7 +505,7 @@ GPUg() void __launch_bounds__(256, 1) computeLayerCellsKernel( break; } - if (!track.correctForMaterial(layerxX0[layer + iC], layerxX0[layer] * constants::Radl * constants::Rho, true)) { + if (!track.correctForMaterial(layerxX0[layer + iC], layerxX0[layer + iC] * constants::Radl * constants::Rho, true)) { break; } diff --git a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx index 15459576a1031..b4ac847863d51 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx @@ -357,7 +357,7 @@ void TrackerTraits::computeLayerCells(const int iteration) break; } - if (!track.correctForMaterial(mTrkParams[0].LayerxX0[iLayer + iC], mTrkParams[0].LayerxX0[iLayer] * constants::Radl * constants::Rho, true)) { + if (!track.correctForMaterial(mTrkParams[0].LayerxX0[iLayer + iC], mTrkParams[0].LayerxX0[iLayer + iC] * constants::Radl * constants::Rho, true)) { break; } From b62d3d6084dc219ffe1e99c8d42042d043c73773 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Wed, 28 Jan 2026 11:10:20 +0100 Subject: [PATCH 128/234] ITS: GPU: create compile time stack tags Signed-off-by: Felix Schlepper --- .../ITS/tracking/GPU/cuda/TimeFrameGPU.cu | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu index c7d6e31ec771a..da0cd51478945 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu @@ -11,7 +11,6 @@ /// #include -#include #include #include @@ -633,21 +632,37 @@ void TimeFrameGPU::unregisterHostMemory(const int maxLayers) checkedUnregisterArray(mPinnedROFramesClusters, mROFramesClustersDevice); } +namespace detail +{ +template +constexpr uint64_t makeIterTag() +{ + static_assert(I < 10); + constexpr char tag[] = {'I', 'T', 'S', 'I', 'T', 'E', 'R', char('0' + I), '\0'}; + return qStr2Tag(tag); +} +template +constexpr auto makeIterTags(std::index_sequence) +{ + return std::array{makeIterTag()...}; +} +// FIXME: we have to be careful that the MaxIter does not diverge from the 4 here! +constexpr auto kIterTags = makeIterTags(std::make_index_sequence<4>{}); +} // namespace detail + template void TimeFrameGPU::pushMemoryStack(const int iteration) { // mark the beginning of memory marked with MEMORY_STACK that can be discarded // after doing one iteration - const auto name = fmt::format("ITSITER{}", iteration); - (this->mExternalAllocator)->pushTagOnStack(qStr2Tag(name.c_str())); + (this->mExternalAllocator)->pushTagOnStack(detail::kIterTags[iteration]); } template void TimeFrameGPU::popMemoryStack(const int iteration) { // pop all memory on the stack from this iteration - const auto name = fmt::format("ITSITER{}", iteration); - (this->mExternalAllocator)->popTagOffStack(qStr2Tag(name.c_str())); + (this->mExternalAllocator)->popTagOffStack(detail::kIterTags[iteration]); } template From 5f4f95a4797a1f5082d3c388fbc05aff8438ba95 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Tue, 27 Jan 2026 19:25:24 +0100 Subject: [PATCH 129/234] GPU: add constexpr version of qStr2Tag Signed-off-by: Felix Schlepper --- GPU/GPUTracking/utils/strtag.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/GPU/GPUTracking/utils/strtag.h b/GPU/GPUTracking/utils/strtag.h index 24c527ca11a8c..a822083da8980 100644 --- a/GPU/GPUTracking/utils/strtag.h +++ b/GPU/GPUTracking/utils/strtag.h @@ -15,20 +15,21 @@ #ifndef STRTAG_H #define STRTAG_H -#include +#include +#include #include +#include -template -constexpr T qStr2Tag(const char* str) +template +constexpr T qStr2Tag(const char (&str)[N]) { - if (strlen(str) != sizeof(T)) { - throw std::runtime_error("Invalid tag length"); + static_assert(std::is_trivially_copyable_v); + static_assert(N - 1 == sizeof(T), "Invalid tag length"); + T value{}; + for (std::size_t i = 0; i < sizeof(T); ++i) { + value |= T(static_cast(str[i])) << (i * 8); } - T tmp; - for (uint32_t i = 0; i < sizeof(T); i++) { - ((char*)&tmp)[i] = str[i]; - } - return tmp; + return value; } template From e4a4f1a0029b3370a50410ee061b6acfa1a83ec1 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Tue, 27 Jan 2026 20:13:38 +0100 Subject: [PATCH 130/234] ITS: GPU: add skipping of parts where nothing was found Signed-off-by: Felix Schlepper --- .../ITS/tracking/GPU/cuda/TrackingKernels.cu | 25 +++++++++++++++---- .../ITS/tracking/GPU/hip/CMakeLists.txt | 2 ++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu index 7c257bc1d0ba1..a12237358c8bd 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu @@ -399,6 +399,11 @@ GPUg() void __launch_bounds__(256, 1) computeLayerCellNeighboursKernel( const int maxCellNeighbours = 1e2) { for (int iCurrentCellIndex = blockIdx.x * blockDim.x + threadIdx.x; iCurrentCellIndex < nCells; iCurrentCellIndex += blockDim.x * gridDim.x) { + if constexpr (!initRun) { + if (neighboursIndexTable[iCurrentCellIndex] == neighboursIndexTable[iCurrentCellIndex + 1]) { + continue; + } + } const auto& currentCellSeed{cellSeedArray[layerIndex][iCurrentCellIndex]}; const int nextLayerTrackletIndex{currentCellSeed.getSecondTrackletIndex()}; const int nextLayerFirstCellIndex{cellsLUTs[layerIndex + 1][nextLayerTrackletIndex]}; @@ -464,8 +469,13 @@ GPUg() void __launch_bounds__(256, 1) computeLayerCellsKernel( const float cellDeltaTanLambdaSigma, const float nSigmaCut) { - constexpr float layerxX0[7] = {5.e-3f, 5.e-3f, 5.e-3f, 1.e-2f, 1.e-2f, 1.e-2f, 1.e-2f}; // Hardcoded here for the moment. + constexpr float layerxX0[7] = {5.e-3f, 5.e-3f, 5.e-3f, 1.e-2f, 1.e-2f, 1.e-2f, 1.e-2f}; // FIXME: Hardcoded here for the moment. for (int iCurrentTrackletIndex = blockIdx.x * blockDim.x + threadIdx.x; iCurrentTrackletIndex < nTrackletsCurrent; iCurrentTrackletIndex += blockDim.x * gridDim.x) { + if constexpr (!initRun) { + if (cellsLUTs[layer][iCurrentTrackletIndex] == cellsLUTs[layer][iCurrentTrackletIndex + 1]) { + continue; + } + } const Tracklet& currentTracklet = tracklets[layer][iCurrentTrackletIndex]; const int nextLayerClusterIndex{currentTracklet.secondClusterIndex}; const int nextLayerFirstTrackletIndex{trackletsLUT[layer + 1][nextLayerClusterIndex]}; @@ -526,11 +536,11 @@ GPUg() void __launch_bounds__(256, 1) computeLayerCellsKernel( new (cells + cellsLUTs[layer][iCurrentTrackletIndex] + foundCells) CellSeed{layer, clusId[0], clusId[1], clusId[2], iCurrentTrackletIndex, iNextTrackletIndex, track, chi2}; } ++foundCells; - if constexpr (initRun) { - cellsLUTs[layer][iCurrentTrackletIndex] = foundCells; - } } } + if constexpr (initRun) { + cellsLUTs[layer][iCurrentTrackletIndex] = foundCells; + } } } @@ -692,8 +702,13 @@ GPUg() void __launch_bounds__(256, 1) processNeighboursKernel( const o2::base::Propagator* propagator, const o2::base::PropagatorF::MatCorrType matCorrType) { - constexpr float layerxX0[7] = {5.e-3f, 5.e-3f, 5.e-3f, 1.e-2f, 1.e-2f, 1.e-2f, 1.e-2f}; // Hardcoded here for the moment. + constexpr float layerxX0[7] = {5.e-3f, 5.e-3f, 5.e-3f, 1.e-2f, 1.e-2f, 1.e-2f, 1.e-2f}; // FIXME: Hardcoded here for the moment. for (unsigned int iCurrentCell = blockIdx.x * blockDim.x + threadIdx.x; iCurrentCell < nCurrentCells; iCurrentCell += blockDim.x * gridDim.x) { + if constexpr (!dryRun) { + if (foundSeedsTable[iCurrentCell] == foundSeedsTable[iCurrentCell + 1]) { + continue; + } + } int foundSeeds{0}; const auto& currentCell{currentCellSeeds[iCurrentCell]}; if (currentCell.getLevel() != level) { diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt b/Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt index e8e475f2232c8..a40aac491a386 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt @@ -13,6 +13,8 @@ if(HIP_ENABLED) message(STATUS "Building ITS HIP tracker") set(CMAKE_HIP_FLAGS "${CMAKE_HIP_FLAGS} -fgpu-rdc") # set(CMAKE_HIP_FLAGS "${CMAKE_HIP_FLAGS} -O0 -g -ggdb -fno-inline -fno-omit-frame-pointer -D__HIP_ENABLE_DEVICE_ASSERT__") + # add_compile_definitions(ITS_MEASURE_GPU_TIME) + # add_compile_definitions(ITS_GPU_LOG) o2_add_hipified_library(ITStrackingHIP SOURCES ../cuda/ClusterLinesGPU.cu ../cuda/TimeFrameGPU.cu From aa3ef3751f282ee477e0636d6bd5697c43103381 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Tue, 27 Jan 2026 20:14:15 +0100 Subject: [PATCH 131/234] ITS: GPU: more memory clearing in processNeighbours Signed-off-by: Felix Schlepper --- .../ITS/tracking/GPU/cuda/TrackingKernels.cu | 84 +++++++++++++------ 1 file changed, 58 insertions(+), 26 deletions(-) diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu index a12237358c8bd..50888c676df77 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu @@ -39,6 +39,7 @@ // O2 track model #include "ReconstructionDataFormats/Track.h" #include "DetectorsBase/Propagator.h" +#include "utils/strtag.h" using namespace o2::track; namespace o2::its @@ -1106,11 +1107,19 @@ void processNeighboursHandler(const int startLayer, const int nBlocks, const int nThreads) { + constexpr uint64_t Tag = qStr2Tag("ITS_PNH1"); + + // allocators used auto allocInt = gpu::TypedAllocator(alloc); auto allocCellSeed = gpu::TypedAllocator>(alloc); - thrust::device_vector> foundSeedsTable(nCells[startLayer] + 1, 0, allocInt); - auto nosync_policy = THRUST_NAMESPACE::par_nosync(gpu::TypedAllocator(alloc)).on(gpu::Stream::DefaultStream); + // use sync_policy, this part cannot be run async but tell thrust to use the allocator + auto sync_policy = THRUST_NAMESPACE::par(gpu::TypedAllocator(alloc)); + + // put initial computation on Tag1 + alloc->pushTagOnStack(Tag); + // start processing of cells + thrust::device_vector> foundSeedsTable(nCells[startLayer] + 1, 0, allocInt); gpu::processNeighboursKernel<<>>( startLayer, startLevel, @@ -1129,10 +1138,10 @@ void processNeighboursHandler(const int startLayer, maxChi2ClusterAttachment, propagator, matCorrType); - thrust::exclusive_scan(nosync_policy, foundSeedsTable.begin(), foundSeedsTable.end(), foundSeedsTable.begin()); - - thrust::device_vector> updatedCellId(foundSeedsTable.back(), 0, allocInt); - thrust::device_vector, gpu::TypedAllocator>> updatedCellSeed(foundSeedsTable.back(), allocCellSeed); + thrust::exclusive_scan(sync_policy, foundSeedsTable.begin(), foundSeedsTable.end(), foundSeedsTable.begin()); + auto foundSeeds{foundSeedsTable.back()}; + thrust::device_vector> updatedCellId(foundSeeds, 0, allocInt); + thrust::device_vector, gpu::TypedAllocator>> updatedCellSeed(foundSeeds, allocCellSeed); gpu::processNeighboursKernel<<>>( startLayer, startLevel, @@ -1151,20 +1160,41 @@ void processNeighboursHandler(const int startLayer, maxChi2ClusterAttachment, propagator, matCorrType); - GPUChkErrS(cudaStreamSynchronize(gpu::Stream::DefaultStream)); + // now do inward steps until stop is reached int level = startLevel; - thrust::device_vector> lastCellId(allocInt); - thrust::device_vector, gpu::TypedAllocator>> lastCellSeed(allocCellSeed); + + // Host buffers to break dependency + // FIXME: these should be on our memory resource! + std::vector hostCellId; + std::vector> hostCellSeed; + + // inward loop for (int iLayer{startLayer - 1}; iLayer > 0 && level > 2; --iLayer) { - lastCellSeed.swap(updatedCellSeed); - lastCellId.swap(updatedCellId); + // copy current results to host + hostCellId.resize(updatedCellId.size()); + hostCellSeed.resize(updatedCellSeed.size()); + thrust::copy(updatedCellId.begin(), updatedCellId.end(), hostCellId.begin()); + thrust::copy(updatedCellSeed.begin(), updatedCellSeed.end(), hostCellSeed.begin()); + + auto lastCellSeedSize{hostCellSeed.size()}; + // but before we clear the memory, and immediately start a new block + alloc->popTagOffStack(Tag); + alloc->pushTagOnStack(Tag); + + // based on the previous step's result create new LUT and zero it + thrust::device_vector>(allocInt).swap(foundSeedsTable); + foundSeedsTable.resize(lastCellSeedSize + 1); + thrust::fill(sync_policy, foundSeedsTable.begin(), foundSeedsTable.end(), 0); + + // recreate lastCell vectors from host + thrust::device_vector> lastCellId(hostCellId.begin(), hostCellId.end(), allocInt); + thrust::device_vector, gpu::TypedAllocator>> lastCellSeed(hostCellSeed.begin(), hostCellSeed.end(), allocCellSeed); + // also create new vectors on new block thrust::device_vector, gpu::TypedAllocator>>(allocCellSeed).swap(updatedCellSeed); thrust::device_vector>(allocInt).swap(updatedCellId); - auto lastCellSeedSize{lastCellSeed.size()}; - foundSeedsTable.resize(lastCellSeedSize + 1); - thrust::fill(nosync_policy, foundSeedsTable.begin(), foundSeedsTable.end(), 0); + // start step gpu::processNeighboursKernel<<>>( iLayer, --level, @@ -1183,14 +1213,13 @@ void processNeighboursHandler(const int startLayer, maxChi2ClusterAttachment, propagator, matCorrType); - thrust::exclusive_scan(nosync_policy, foundSeedsTable.begin(), foundSeedsTable.end(), foundSeedsTable.begin()); - - auto foundSeeds{foundSeedsTable.back()}; + // how many new seeds where found + thrust::exclusive_scan(sync_policy, foundSeedsTable.begin(), foundSeedsTable.end(), foundSeedsTable.begin()); + foundSeeds = foundSeedsTable.back(); + // do a resize, we don't need to set the memory now since we know that all of these are written to + // Note though this does not clear the memory... updatedCellId.resize(foundSeeds); - thrust::fill(nosync_policy, updatedCellId.begin(), updatedCellId.end(), 0); updatedCellSeed.resize(foundSeeds); - thrust::fill(nosync_policy, updatedCellSeed.begin(), updatedCellSeed.end(), CellSeed()); - gpu::processNeighboursKernel<<>>( iLayer, level, @@ -1210,12 +1239,15 @@ void processNeighboursHandler(const int startLayer, propagator, matCorrType); } - GPUChkErrS(cudaStreamSynchronize(gpu::Stream::DefaultStream)); - thrust::device_vector, gpu::TypedAllocator>> outSeeds(updatedCellSeed.size(), allocCellSeed); - auto end = thrust::copy_if(nosync_policy, updatedCellSeed.begin(), updatedCellSeed.end(), outSeeds.begin(), gpu::seed_selector(1.e3, maxChi2NDF * ((startLevel + 2) * 2 - 5))); - auto s{end - outSeeds.begin()}; - seedsHost.reserve(seedsHost.size() + s); - thrust::copy(outSeeds.begin(), outSeeds.begin() + s, std::back_inserter(seedsHost)); + + // final copy of result + const auto selector = gpu::seed_selector(1.e3, maxChi2NDF * ((startLevel + 2) * 2 - 5)); + const auto count = thrust::count_if(sync_policy, updatedCellSeed.begin(), updatedCellSeed.end(), selector); + thrust::device_vector, gpu::TypedAllocator>> outSeeds(count, allocCellSeed); + thrust::copy_if(sync_policy, updatedCellSeed.begin(), updatedCellSeed.end(), outSeeds.begin(), selector); + seedsHost.reserve(seedsHost.size() + count); + thrust::copy(outSeeds.begin(), outSeeds.end(), std::back_inserter(seedsHost)); + alloc->popTagOffStack(Tag); } template From 0bb564d94f58153218e6cb421a5c666239c44428 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Wed, 28 Jan 2026 12:35:23 +0100 Subject: [PATCH 132/234] ITS: GPU: fix wrong argument parsing for outward refit Signed-off-by: Felix Schlepper --- Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx | 4 ++-- .../ITSMFT/ITS/tracking/include/ITStracking/Configuration.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx index 60774e3313d7f..42d2227de60f8 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx @@ -337,8 +337,8 @@ void TrackerTraitsGPU::findRoads(const int iteration) startLevel, this->mTrkParams[0].MaxChi2ClusterAttachment, this->mTrkParams[0].MaxChi2NDF, - this->mTrkParams[0].RepeatRefitOut, this->mTrkParams[0].ReseedIfShorter, + this->mTrkParams[0].RepeatRefitOut, this->mTrkParams[0].ShiftRefToCluster, mTimeFrameGPU->getDevicePropagator(), this->mTrkParams[0].CorrType, @@ -359,8 +359,8 @@ void TrackerTraitsGPU::findRoads(const int iteration) startLevel, this->mTrkParams[0].MaxChi2ClusterAttachment, this->mTrkParams[0].MaxChi2NDF, - this->mTrkParams[0].RepeatRefitOut, this->mTrkParams[0].ReseedIfShorter, + this->mTrkParams[0].RepeatRefitOut, this->mTrkParams[0].ShiftRefToCluster, mTimeFrameGPU->getDevicePropagator(), this->mTrkParams[0].CorrType, diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h index 1c4d604a629ed..10e1681c73e8d 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h @@ -69,7 +69,7 @@ struct TrackingParameters { int ReseedIfShorter = 6; // reseed for the final fit track with the length shorter than this std::vector MinPt = {0.f, 0.f, 0.f, 0.f}; uint16_t StartLayerMask = 0x7F; - bool RepeatRefitOut = true; // repeat outward refit using inward refit as a seed + bool RepeatRefitOut = false; // repeat outward refit using inward refit as a seed bool ShiftRefToCluster = true; // TrackFit: after update shift the linearization reference to cluster bool FindShortTracks = false; bool PerPrimaryVertexProcessing = false; From 63e5c6136f9eb261968541ae80cc589d2c1b0a7f Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Thu, 29 Jan 2026 13:44:05 +0100 Subject: [PATCH 133/234] DPL Analysis: cleanup AnalysisTask.h and ASoA.h (#14996) * remove unnecessary include; unnecessary mutability; too specific requires; unused function * use non-capturing lambdas; restrict template * we only expect void process functions * improve getIterators * improve homogeneous_apply_ref --------- Co-authored-by: ALICE Action Bot --- Framework/Core/include/Framework/ASoA.h | 62 +++---- .../Core/include/Framework/AnalysisManagers.h | 6 - .../Core/include/Framework/AnalysisTask.h | 163 +++++++++--------- .../include/Framework/StructToTuple.h | 46 ++--- 4 files changed, 128 insertions(+), 149 deletions(-) diff --git a/Framework/Core/include/Framework/ASoA.h b/Framework/Core/include/Framework/ASoA.h index 4fd35e0dc5065..7586d6a6d3c63 100644 --- a/Framework/Core/include/Framework/ASoA.h +++ b/Framework/Core/include/Framework/ASoA.h @@ -405,15 +405,15 @@ class Table; /// Type-checking index column binding struct Binding { void const* ptr = nullptr; - size_t hash = 0; - std::span refs; + uint32_t hash = 0; + // std::span refs; template void bind(T const* table) { ptr = table; hash = o2::framework::TypeIdHelpers::uniqueId(); - refs = std::span{T::originals}; + // refs = std::span{T::originals}; } template @@ -1293,6 +1293,9 @@ struct ArrowHelpers { template concept is_iterator = framework::base_of_template || framework::specialization_of_template; +template +concept is_table_or_iterator = is_table || is_iterator; + template concept with_originals = requires { T::originals.size(); @@ -2724,7 +2727,7 @@ consteval auto getIndexTargets() return !(*mColumnIterator).empty(); \ } \ \ - template \ + template \ auto _Getter_##_as() const \ { \ if (O2_BUILTIN_UNLIKELY(mBinding.ptr == nullptr)) { \ @@ -2734,10 +2737,15 @@ consteval auto getIndexTargets() if (O2_BUILTIN_UNLIKELY(t == nullptr)) { \ o2::soa::dereferenceWithWrongType(#_Getter_, #_Table_); \ } \ - return getIterators(); \ + auto result = std::vector(); \ + result.reserve((*mColumnIterator).size()); \ + for (auto& i : *mColumnIterator) { \ + result.emplace_back(t->rawIteratorAt(i)); \ + } \ + return result; \ } \ \ - template \ + template \ auto filtered_##_Getter_##_as() const \ { \ if (O2_BUILTIN_UNLIKELY(mBinding.ptr == nullptr)) { \ @@ -2747,35 +2755,15 @@ consteval auto getIndexTargets() if (O2_BUILTIN_UNLIKELY(t == nullptr)) { \ o2::soa::dereferenceWithWrongType(#_Getter_, #_Table_); \ } \ - return getFilteredIterators(); \ - } \ - \ - template \ - auto getIterators() const \ - { \ - auto result = std::vector(); \ - for (auto& i : *mColumnIterator) { \ - result.push_back(mBinding.get()->rawIteratorAt(i)); \ - } \ - return result; \ - } \ - \ - template \ - std::vector getFilteredIterators() const \ - { \ - if constexpr (o2::soa::is_filtered_table) { \ - auto result = std::vector(); \ - for (auto const& i : *mColumnIterator) { \ - auto pos = mBinding.get()->isInSelectedRows(i); \ - if (pos > 0) { \ - result.emplace_back(mBinding.get()->iteratorAt(pos)); \ - } \ + auto result = std::vector(); \ + result.reserve((*mColumnIterator).size()); \ + for (auto const& i : *mColumnIterator) { \ + auto pos = t->isInSelectedRows(i); \ + if (pos > 0) { \ + result.emplace_back(t->iteratorAt(pos)); \ } \ - return result; \ - } else { \ - static_assert(o2::framework::always_static_assert_v, "T is not a Filtered type"); \ } \ - return {}; \ + return result; \ } \ \ auto _Getter_() const \ @@ -3090,15 +3078,9 @@ consteval auto getIndexTargets() if (O2_BUILTIN_UNLIKELY(t == nullptr)) { \ o2::soa::dereferenceWithWrongType(#_Getter_, "self"); \ } \ - return getIterators(); \ - } \ - \ - template \ - auto getIterators() const \ - { \ auto result = std::vector(); \ for (auto& i : *mColumnIterator) { \ - result.push_back(mBinding.get()->rawIteratorAt(i)); \ + result.push_back(t->rawIteratorAt(i)); \ } \ return result; \ } \ diff --git a/Framework/Core/include/Framework/AnalysisManagers.h b/Framework/Core/include/Framework/AnalysisManagers.h index fd41a079c6570..121ce7f4b4a77 100644 --- a/Framework/Core/include/Framework/AnalysisManagers.h +++ b/Framework/Core/include/Framework/AnalysisManagers.h @@ -534,12 +534,6 @@ void bindExternalIndicesPartition(P& partition, T*... tables) } /// Cache handling -template -bool preInitializeCache(InitContext&, T&) -{ - return false; -} - template bool initializeCache(ProcessingContext&, T&) { diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index 4f8a9e719e4b9..365c6b1d41692 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -22,7 +22,6 @@ #include "Framework/EndOfStreamContext.h" #include "Framework/GroupSlicer.h" #include "Framework/StructToTuple.h" -#include "Framework/Traits.h" #include "Framework/TypeIdHelpers.h" #include "Framework/ArrowTableSlicingCache.h" #include "Framework/AnalysisDataModel.h" @@ -63,17 +62,20 @@ static constexpr bool is_enumeration_v> = true; template concept is_enumeration = is_enumeration_v>; +template +concept is_table_iterator_or_enumeration = soa::is_table_or_iterator || is_enumeration; + // Helper struct which builds a DataProcessorSpec from // the contents of an AnalysisTask... namespace { struct AnalysisDataProcessorBuilder { - template + template static void addGroupingCandidates(Cache& bk, Cache& bku, bool enabled) { - [&bk, &bku, enabled](framework::pack) mutable { + [](framework::pack, Cache& bk, Cache& bku, bool enabled) { auto key = std::string{"fIndex"} + o2::framework::cutString(soa::getLabelFromType>()); - ([&bk, &bku, &key, enabled]() mutable { + ([](Cache& bk, Cache& bku, bool enabled, std::string const& key) { if constexpr (soa::relatedByIndex, std::decay_t>()) { Entry e{soa::getLabelFromTypeForKey>(key), soa::getMatcherFromTypeForKey>(key), key, enabled}; if constexpr (o2::soa::is_smallgroups>) { @@ -82,9 +84,9 @@ struct AnalysisDataProcessorBuilder { framework::updatePairList(bk, e); } } - }(), + }(bk, bku, enabled, key), ...); - }(framework::pack{}); + }(framework::pack{}, bk, bku, enabled); } template @@ -168,8 +170,8 @@ struct AnalysisDataProcessorBuilder { return true; } /// 1. enumeration (must be the only argument) - template - static void inputsFromArgs(R (C::*)(A), const char* /*name*/, bool /*value*/, std::vector& inputs, std::vector&) //, Cache&, Cache&) + template + static void inputsFromArgs(void (C::*)(A), const char* /*name*/, bool /*value*/, std::vector& inputs, std::vector&) //, Cache&, Cache&) { std::vector inputMetadata; // FIXME: for the moment we do not support begin, end and step. @@ -177,37 +179,37 @@ struct AnalysisDataProcessorBuilder { } /// 2. 1st argument is an iterator - template - static void inputsFromArgs(R (C::*)(A, Args...), const char* name, bool value, std::vector& inputs, std::vector& eInfos) //, Cache& bk, Cache& bku) + template + static void inputsFromArgs(void (C::*)(A, Args...), const char* name, bool value, std::vector& inputs, std::vector& eInfos) //, Cache& bk, Cache& bku) requires(std::is_lvalue_reference_v && (std::is_lvalue_reference_v && ...)) { - constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); + constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); addInputsAndExpressions::parent_t, Args...>(hash, name, value, inputs, eInfos); } /// 3. generic case - template - static void inputsFromArgs(R (C::*)(Args...), const char* name, bool value, std::vector& inputs, std::vector& eInfos) //, Cache&, Cache&) + template + static void inputsFromArgs(void (C::*)(Args...), const char* name, bool value, std::vector& inputs, std::vector& eInfos) //, Cache&, Cache&) requires(std::is_lvalue_reference_v && ...) { - constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); + constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); addInputsAndExpressions(hash, name, value, inputs, eInfos); } /// 1. enumeration (no grouping) - template - static void cacheFromArgs(R (C::*)(A), bool, Cache&, Cache&) + template + static void cacheFromArgs(void (C::*)(A), bool, Cache&, Cache&) { } /// 2. iterator (the only grouping case) - template - static void cacheFromArgs(R (C::*)(A, Args...), bool value, Cache& bk, Cache& bku) + template + static void cacheFromArgs(void (C::*)(A, Args...), bool value, Cache& bk, Cache& bku) { addGroupingCandidates(bk, bku, value); } /// 3. generic case (no grouping) - template - static void cacheFromArgs(R (C::*)(A, Args...), bool, Cache&, Cache&) + template + static void cacheFromArgs(void (C::*)(A, Args...), bool, Cache&, Cache&) { } @@ -282,51 +284,53 @@ struct AnalysisDataProcessorBuilder { } } - template - static auto bindGroupingTable(InputRecord& record, R (C::*)(Grouping, Args...), std::vector& infos) + template + static auto bindGroupingTable(InputRecord& record, void (C::*)(Grouping, Args...), std::vector& infos) requires(!std::same_as) { - constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); + constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); return extract, 0>(record, infos, hash); } - template - static auto bindAssociatedTables(InputRecord& record, R (C::*)(Grouping, Args...), std::vector& infos) + template + static auto bindAssociatedTables(InputRecord& record, void (C::*)(Grouping, Args...), std::vector& infos) requires(!std::same_as && sizeof...(Args) > 0) { constexpr auto p = pack{}; - constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); + constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); return std::make_tuple(extract, has_type_at_v(p) + 1>(record, infos, hash)...); } - template + template static void overwriteInternalIndices(std::tuple& dest, std::tuple const& src) { (std::get(dest).bindInternalIndicesTo(&std::get(src)), ...); } - template - static void invokeProcess(Task& task, InputRecord& inputs, R (C::*processingFunction)(Grouping, Associated...), std::vector& infos, ArrowTableSlicingCache& slices) + template + static void invokeProcess(Task& task, InputRecord& inputs, void (Task::*processingFunction)(Grouping, Associated...), std::vector& infos, ArrowTableSlicingCache& slices) { using G = std::decay_t; auto groupingTable = AnalysisDataProcessorBuilder::bindGroupingTable(inputs, processingFunction, infos); + constexpr const int numElements = nested_brace_constructible_size>() / 10; + // set filtered tables for partitions with grouping - homogeneous_apply_refs([&groupingTable](auto& element) { + homogeneous_apply_refs_sized([&groupingTable](auto& element) { analysis_task_parsers::setPartition(element, groupingTable); analysis_task_parsers::bindInternalIndicesPartition(element, &groupingTable); return true; }, - task); + task); if constexpr (sizeof...(Associated) == 0) { // single argument to process - homogeneous_apply_refs([&groupingTable](auto& element) { + homogeneous_apply_refs_sized([&groupingTable](auto& element) { analysis_task_parsers::bindExternalIndicesPartition(element, &groupingTable); analysis_task_parsers::setGroupedCombination(element, groupingTable); return true; }, - task); + task); if constexpr (soa::is_iterator) { for (auto& element : groupingTable) { std::invoke(processingFunction, task, *element); @@ -344,7 +348,7 @@ struct AnalysisDataProcessorBuilder { // pre-bind self indices std::apply( [&task](auto&... t) mutable { - (homogeneous_apply_refs( + (homogeneous_apply_refs_sized( [&t](auto& p) { analysis_task_parsers::bindInternalIndicesPartition(p, &t); return true; @@ -356,12 +360,12 @@ struct AnalysisDataProcessorBuilder { auto binder = [&task, &groupingTable, &associatedTables](auto& x) mutable { x.bindExternalIndices(&groupingTable, &std::get>(associatedTables)...); - homogeneous_apply_refs([&x](auto& t) mutable { + homogeneous_apply_refs_sized([&x](auto& t) mutable { analysis_task_parsers::setPartition(t, x); analysis_task_parsers::bindExternalIndicesPartition(t, &x); return true; }, - task); + task); }; groupingTable.bindExternalIndices(&std::get>(associatedTables)...); @@ -373,11 +377,11 @@ struct AnalysisDataProcessorBuilder { associatedTables); // GroupedCombinations bound separately, as they should be set once for all associated tables - homogeneous_apply_refs([&groupingTable, &associatedTables](auto& t) { + homogeneous_apply_refs_sized([&groupingTable, &associatedTables](auto& t) { analysis_task_parsers::setGroupedCombination(t, groupingTable, associatedTables); return true; }, - task); + task); overwriteInternalIndices(associatedTables, associatedTables); if constexpr (soa::is_iterator>) { auto slicer = GroupSlicer(groupingTable, associatedTables, slices); @@ -391,28 +395,28 @@ struct AnalysisDataProcessorBuilder { associatedSlices); // bind partitions and grouping table - homogeneous_apply_refs([&groupingTable](auto& x) { + homogeneous_apply_refs_sized([&groupingTable](auto& x) { analysis_task_parsers::bindExternalIndicesPartition(x, &groupingTable); return true; }, - task); + task); invokeProcessWithArgs(task, processingFunction, slice.groupingElement(), associatedSlices); } } else { // bind partitions and grouping table - homogeneous_apply_refs([&groupingTable](auto& x) { + homogeneous_apply_refs_sized([&groupingTable](auto& x) { analysis_task_parsers::bindExternalIndicesPartition(x, &groupingTable); return true; }, - task); + task); invokeProcessWithArgs(task, processingFunction, groupingTable, associatedTables); } } } - template + template static void invokeProcessWithArgs(C& task, T processingFunction, G g, std::tuple& at) { std::invoke(processingFunction, task, g, std::get(at)...); @@ -520,16 +524,18 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) std::vector options; std::vector expressionInfos; + constexpr const int numElements = nested_brace_constructible_size>() / 10; + /// make sure options and configurables are set before expression infos are created - homogeneous_apply_refs([&options](auto& element) { return analysis_task_parsers::appendOption(options, element); }, *task.get()); + homogeneous_apply_refs_sized([&options](auto& element) { return analysis_task_parsers::appendOption(options, element); }, *task.get()); /// extract conditions and append them as inputs - homogeneous_apply_refs([&inputs](auto& element) { return analysis_task_parsers::appendCondition(inputs, element); }, *task.get()); + homogeneous_apply_refs_sized([&inputs](auto& element) { return analysis_task_parsers::appendCondition(inputs, element); }, *task.get()); /// parse process functions defined by corresponding configurables if constexpr (requires { &T::process; }) { AnalysisDataProcessorBuilder::inputsFromArgs(&T::process, "default", true, inputs, expressionInfos); } - homogeneous_apply_refs( + homogeneous_apply_refs_sized( [name = name_str, &expressionInfos, &inputs](auto& x) mutable { // this pushes (argumentIndex, processHash, schemaPtr, nullptr) into expressionInfos for arguments that are Filtered/filtered_iterators return AnalysisDataProcessorBuilder::requestInputsFromArgs(x, name, inputs, expressionInfos); @@ -538,39 +544,39 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) // request base tables for spawnable extended tables and indices to be built // this checks for duplications - homogeneous_apply_refs([&inputs](auto& element) { + homogeneous_apply_refs_sized([&inputs](auto& element) { return analysis_task_parsers::requestInputs(inputs, element); }, - *task.get()); + *task.get()); // no static way to check if the task defines any processing, we can only make sure it subscribes to at least something if (inputs.empty() == true) { LOG(warn) << "Task " << name_str << " has no inputs"; } - homogeneous_apply_refs([&outputs, &hash](auto& element) { return analysis_task_parsers::appendOutput(outputs, element, hash); }, *task.get()); + homogeneous_apply_refs_sized([&outputs, &hash](auto& element) { return analysis_task_parsers::appendOutput(outputs, element, hash); }, *task.get()); auto requiredServices = CommonServices::defaultServices(); auto arrowServices = CommonServices::arrowServices(); requiredServices.insert(requiredServices.end(), arrowServices.begin(), arrowServices.end()); - homogeneous_apply_refs([&requiredServices](auto& element) { return analysis_task_parsers::addService(requiredServices, element); }, *task.get()); + homogeneous_apply_refs_sized([&requiredServices](auto& element) { return analysis_task_parsers::addService(requiredServices, element); }, *task.get()); auto algo = AlgorithmSpec::InitCallback{[task = task, expressionInfos](InitContext& ic) mutable { Cache bindingsKeys; Cache bindingsKeysUnsorted; // add preslice declarations to slicing cache definition - homogeneous_apply_refs([&bindingsKeys, &bindingsKeysUnsorted](auto& element) { return analysis_task_parsers::registerCache(element, bindingsKeys, bindingsKeysUnsorted); }, *task.get()); + homogeneous_apply_refs_sized([&bindingsKeys, &bindingsKeysUnsorted](auto& element) { return analysis_task_parsers::registerCache(element, bindingsKeys, bindingsKeysUnsorted); }, *task.get()); - homogeneous_apply_refs([&ic](auto&& element) { return analysis_task_parsers::prepareOption(ic, element); }, *task.get()); - homogeneous_apply_refs([&ic](auto&& element) { return analysis_task_parsers::prepareService(ic, element); }, *task.get()); + homogeneous_apply_refs_sized([&ic](auto&& element) { return analysis_task_parsers::prepareOption(ic, element); }, *task.get()); + homogeneous_apply_refs_sized([&ic](auto&& element) { return analysis_task_parsers::prepareService(ic, element); }, *task.get()); auto& callbacks = ic.services().get(); auto eoscb = [task](EndOfStreamContext& eosContext) { - homogeneous_apply_refs([&eosContext](auto& element) { + homogeneous_apply_refs_sized([&eosContext](auto& element) { analysis_task_parsers::postRunService(eosContext, element); analysis_task_parsers::postRunOutput(eosContext, element); return true; }, - *task.get()); + *task.get()); eosContext.services().get().readyToQuit(QuitRequest::Me); }; @@ -582,84 +588,75 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) } /// update configurables in filters and partitions - homogeneous_apply_refs( + homogeneous_apply_refs_sized( [&ic](auto& element) -> bool { return analysis_task_parsers::updatePlaceholders(ic, element); }, *task.get()); /// create expression trees for filters gandiva trees matched to schemas and store the pointers into expressionInfos - homogeneous_apply_refs([&expressionInfos](auto& element) { + homogeneous_apply_refs_sized([&expressionInfos](auto& element) { return analysis_task_parsers::createExpressionTrees(expressionInfos, element); }, - *task.get()); + *task.get()); /// parse process functions to enable requested grouping caches - note that at this state process configurables have their final values if constexpr (requires { &T::process; }) { AnalysisDataProcessorBuilder::cacheFromArgs(&T::process, true, bindingsKeys, bindingsKeysUnsorted); } - homogeneous_apply_refs( - [&bindingsKeys, &bindingsKeysUnsorted](auto& x) mutable { + homogeneous_apply_refs_sized( + [&bindingsKeys, &bindingsKeysUnsorted](auto& x) { return AnalysisDataProcessorBuilder::requestCacheFromArgs(x, bindingsKeys, bindingsKeysUnsorted); }, *task.get()); ic.services().get().setCaches(std::move(bindingsKeys)); ic.services().get().setCachesUnsorted(std::move(bindingsKeysUnsorted)); - // initialize global caches - homogeneous_apply_refs([&ic](auto& element) { - return analysis_task_parsers::preInitializeCache(ic, element); - }, - *(task.get())); return [task, expressionInfos](ProcessingContext& pc) mutable { // load the ccdb object from their cache - homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::newDataframeCondition(pc.inputs(), element); }, *task.get()); + homogeneous_apply_refs_sized([&pc](auto& element) { return analysis_task_parsers::newDataframeCondition(pc.inputs(), element); }, *task.get()); // reset partitions once per dataframe - homogeneous_apply_refs([](auto& element) { return analysis_task_parsers::newDataframePartition(element); }, *task.get()); + homogeneous_apply_refs_sized([](auto& element) { return analysis_task_parsers::newDataframePartition(element); }, *task.get()); // reset selections for the next dataframe - for (auto& info : expressionInfos) { - info.resetSelection = true; - } + std::ranges::for_each(expressionInfos, [](auto& info) { info.resetSelection = true; }); // reset pre-slice for the next dataframe auto slices = pc.services().get(); - homogeneous_apply_refs([&slices](auto& element) { + homogeneous_apply_refs_sized([&slices](auto& element) { return analysis_task_parsers::updateSliceInfo(element, slices); }, - *(task.get())); + *(task.get())); // initialize local caches - homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::initializeCache(pc, element); }, *(task.get())); + homogeneous_apply_refs_sized([&pc](auto& element) { return analysis_task_parsers::initializeCache(pc, element); }, *(task.get())); // prepare outputs - homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::prepareOutput(pc, element); }, *task.get()); + homogeneous_apply_refs_sized([&pc](auto& element) { return analysis_task_parsers::prepareOutput(pc, element); }, *task.get()); // execute run() if constexpr (requires { task->run(pc); }) { task->run(pc); } // execute process() - if constexpr (requires { AnalysisDataProcessorBuilder::invokeProcess(*(task.get()), pc.inputs(), &T::process, expressionInfos, slices); }) { + if constexpr (requires { &T::process; }) { AnalysisDataProcessorBuilder::invokeProcess(*(task.get()), pc.inputs(), &T::process, expressionInfos, slices); } // execute optional process() - homogeneous_apply_refs( - [&pc, &expressionInfos, &task, &slices](auto& x) mutable { - if constexpr (base_of_template>) { + homogeneous_apply_refs_sized( + [&pc, &expressionInfos, &task, &slices](auto& x) { + if constexpr (is_process_configurable) { if (x.value == true) { AnalysisDataProcessorBuilder::invokeProcess(*task.get(), pc.inputs(), x.process, expressionInfos, slices); return true; } + return false; } return false; }, *task.get()); // prepare delayed outputs - homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::prepareDelayedOutput(pc, element); }, *task.get()); + homogeneous_apply_refs_sized([&pc](auto& element) { return analysis_task_parsers::prepareDelayedOutput(pc, element); }, *task.get()); // finalize outputs - homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::finalizeOutput(pc, element); }, *task.get()); + homogeneous_apply_refs_sized([&pc](auto& element) { return analysis_task_parsers::finalizeOutput(pc, element); }, *task.get()); }; }}; return { name, - // FIXME: For the moment we hardcode this. We could build - // this list from the list of methods actually implemented in the - // task itself. inputs, outputs, algo, diff --git a/Framework/Foundation/include/Framework/StructToTuple.h b/Framework/Foundation/include/Framework/StructToTuple.h index 5748329f6a50d..1c7aa62260bd3 100644 --- a/Framework/Foundation/include/Framework/StructToTuple.h +++ b/Framework/Foundation/include/Framework/StructToTuple.h @@ -174,9 +174,9 @@ consteval int nested_brace_constructible_size() return brace_constructible_size() - nesting; } -template () / 10> +template () / 10, typename L> requires(D == 9) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -194,9 +194,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 8) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -214,9 +214,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 7) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -234,9 +234,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 6) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -254,9 +254,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 5) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -274,9 +274,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 4) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -294,9 +294,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 3) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -314,9 +314,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 2) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -334,9 +334,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 1) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -354,9 +354,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 0) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -373,6 +373,12 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } +template +constexpr auto homogeneous_apply_refs_sized(L l, T&& object) +{ + return homogeneous_apply_refs(l, object); +} + } // namespace o2::framework #endif // O2_FRAMEWORK_STRUCTTOTUPLE_H_ From a979c459f80ce84473fcc430700f82e5f352f433 Mon Sep 17 00:00:00 2001 From: Ernst Hellbar Date: Fri, 16 Jan 2026 14:05:07 +0100 Subject: [PATCH 134/234] dpl-workflow.sh: enable ALPIDE_ERR_DUMPS by default in online physics runs --- prodtests/full-system-test/dpl-workflow.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index f55605d1da485..f559fcdf91cf5 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -106,7 +106,8 @@ EVE_OPT=" --jsons-folder $EDJSONS_DIR" : ${ITSTPC_CONFIG_KEY:=} : ${AOD_SOURCES:=$TRACK_SOURCES} : ${AODPROD_OPT:=} -: ${ALPIDE_ERR_DUMPS:=0} +: ${ALPIDE_ERR_DUMPS:=} +[[ -z $ALPIDE_ERR_DUMPS ]] && [[ $EPNSYNCMODE == 1 && $RUNTYPE == "PHYSICS" ]] && ALPIDE_ERR_DUMPS=1 || ALPIDE_ERR_DUMPS=0 [[ "0$DISABLE_ROOT_OUTPUT" == "00" ]] && DISABLE_ROOT_OUTPUT= From fd54f4a12076c934e1359a0da6dffed4a0649578 Mon Sep 17 00:00:00 2001 From: ehellbar Date: Fri, 30 Jan 2026 11:03:46 +0100 Subject: [PATCH 135/234] DPL: fix device signpost segfaults for o2-dpl-raw-proxy (#15003) --- Framework/Core/src/DataProcessingDevice.cxx | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index fd03b7725d847..8a306c7b96001 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -1509,9 +1509,8 @@ void DataProcessingDevice::doPrepare(ServiceRegistryRef ref) for (auto sci : pollOrder) { auto& info = state.inputChannelInfos[sci]; - auto& channelSpec = spec.inputChannels[sci]; O2_SIGNPOST_ID_FROM_POINTER(cid, device, &info); - O2_SIGNPOST_START(device, cid, "channels", "Processing channel %s", channelSpec.name.c_str()); + O2_SIGNPOST_START(device, cid, "channels", "Processing channel %s", info.channel->GetName().c_str()); if (info.state != InputChannelState::Completed && info.state != InputChannelState::Pull) { context.allDone = false; @@ -1523,18 +1522,18 @@ void DataProcessingDevice::doPrepare(ServiceRegistryRef ref) DataProcessingDevice::handleData(ref, info); } O2_SIGNPOST_END(device, cid, "channels", "Flushing channel %s which is in state %d and has %zu parts still pending.", - channelSpec.name.c_str(), (int)info.state, info.parts.Size()); + info.channel->GetName().c_str(), (int)info.state, info.parts.Size()); continue; } if (info.channel == nullptr) { O2_SIGNPOST_END(device, cid, "channels", "Channel %s which is in state %d is nullptr and has %zu parts still pending.", - channelSpec.name.c_str(), (int)info.state, info.parts.Size()); + info.channel->GetName().c_str(), (int)info.state, info.parts.Size()); continue; } // Only poll DPL channels for now. if (info.channelType != ChannelAccountingType::DPL) { O2_SIGNPOST_END(device, cid, "channels", "Channel %s which is in state %d is not a DPL channel and has %zu parts still pending.", - channelSpec.name.c_str(), (int)info.state, info.parts.Size()); + info.channel->GetName().c_str(), (int)info.state, info.parts.Size()); continue; } auto& socket = info.channel->GetSocket(); @@ -1546,7 +1545,7 @@ void DataProcessingDevice::doPrepare(ServiceRegistryRef ref) socket.Events(&info.hasPendingEvents); // If we do not read, we can continue. if ((info.hasPendingEvents & 1) == 0 && (info.parts.Size() == 0)) { - O2_SIGNPOST_END(device, cid, "channels", "No pending events and no remaining parts to process for channel %{public}s", channelSpec.name.c_str()); + O2_SIGNPOST_END(device, cid, "channels", "No pending events and no remaining parts to process for channel %{public}s", info.channel->GetName().c_str()); continue; } } @@ -1564,12 +1563,12 @@ void DataProcessingDevice::doPrepare(ServiceRegistryRef ref) bool newMessages = false; while (true) { O2_SIGNPOST_EVENT_EMIT(device, cid, "channels", "Receiving loop called for channel %{public}s (%d) with oldest possible timeslice %zu", - channelSpec.name.c_str(), info.id.value, info.oldestForChannel.value); + info.channel->GetName().c_str(), info.id.value, info.oldestForChannel.value); if (info.parts.Size() < 64) { fair::mq::Parts parts; info.channel->Receive(parts, 0); if (parts.Size()) { - O2_SIGNPOST_EVENT_EMIT(device, cid, "channels", "Received %zu parts from channel %{public}s (%d).", parts.Size(), channelSpec.name.c_str(), info.id.value); + O2_SIGNPOST_EVENT_EMIT(device, cid, "channels", "Received %zu parts from channel %{public}s (%d).", parts.Size(), info.channel->GetName().c_str(), info.id.value); } for (auto&& part : parts) { info.parts.fParts.emplace_back(std::move(part)); @@ -1598,7 +1597,7 @@ void DataProcessingDevice::doPrepare(ServiceRegistryRef ref) } } O2_SIGNPOST_END(device, cid, "channels", "Done processing channel %{public}s (%d).", - channelSpec.name.c_str(), info.id.value); + info.channel->GetName().c_str(), info.id.value); } } From 515ba3a699331dbd7a6c772ce8405ef49a492a99 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Fri, 30 Jan 2026 12:05:55 +0100 Subject: [PATCH 136/234] Revert "DPL Analysis: cleanup AnalysisTask.h and ASoA.h (#14996)" (#15005) This reverts commit 63e5c6136f9eb261968541ae80cc589d2c1b0a7f. --- Framework/Core/include/Framework/ASoA.h | 62 ++++--- .../Core/include/Framework/AnalysisManagers.h | 6 + .../Core/include/Framework/AnalysisTask.h | 163 +++++++++--------- .../include/Framework/StructToTuple.h | 46 +++-- 4 files changed, 149 insertions(+), 128 deletions(-) diff --git a/Framework/Core/include/Framework/ASoA.h b/Framework/Core/include/Framework/ASoA.h index 7586d6a6d3c63..4fd35e0dc5065 100644 --- a/Framework/Core/include/Framework/ASoA.h +++ b/Framework/Core/include/Framework/ASoA.h @@ -405,15 +405,15 @@ class Table; /// Type-checking index column binding struct Binding { void const* ptr = nullptr; - uint32_t hash = 0; - // std::span refs; + size_t hash = 0; + std::span refs; template void bind(T const* table) { ptr = table; hash = o2::framework::TypeIdHelpers::uniqueId(); - // refs = std::span{T::originals}; + refs = std::span{T::originals}; } template @@ -1293,9 +1293,6 @@ struct ArrowHelpers { template concept is_iterator = framework::base_of_template || framework::specialization_of_template; -template -concept is_table_or_iterator = is_table || is_iterator; - template concept with_originals = requires { T::originals.size(); @@ -2727,7 +2724,7 @@ consteval auto getIndexTargets() return !(*mColumnIterator).empty(); \ } \ \ - template \ + template \ auto _Getter_##_as() const \ { \ if (O2_BUILTIN_UNLIKELY(mBinding.ptr == nullptr)) { \ @@ -2737,15 +2734,10 @@ consteval auto getIndexTargets() if (O2_BUILTIN_UNLIKELY(t == nullptr)) { \ o2::soa::dereferenceWithWrongType(#_Getter_, #_Table_); \ } \ - auto result = std::vector(); \ - result.reserve((*mColumnIterator).size()); \ - for (auto& i : *mColumnIterator) { \ - result.emplace_back(t->rawIteratorAt(i)); \ - } \ - return result; \ + return getIterators(); \ } \ \ - template \ + template \ auto filtered_##_Getter_##_as() const \ { \ if (O2_BUILTIN_UNLIKELY(mBinding.ptr == nullptr)) { \ @@ -2755,17 +2747,37 @@ consteval auto getIndexTargets() if (O2_BUILTIN_UNLIKELY(t == nullptr)) { \ o2::soa::dereferenceWithWrongType(#_Getter_, #_Table_); \ } \ - auto result = std::vector(); \ - result.reserve((*mColumnIterator).size()); \ - for (auto const& i : *mColumnIterator) { \ - auto pos = t->isInSelectedRows(i); \ - if (pos > 0) { \ - result.emplace_back(t->iteratorAt(pos)); \ - } \ + return getFilteredIterators(); \ + } \ + \ + template \ + auto getIterators() const \ + { \ + auto result = std::vector(); \ + for (auto& i : *mColumnIterator) { \ + result.push_back(mBinding.get()->rawIteratorAt(i)); \ } \ return result; \ } \ \ + template \ + std::vector getFilteredIterators() const \ + { \ + if constexpr (o2::soa::is_filtered_table) { \ + auto result = std::vector(); \ + for (auto const& i : *mColumnIterator) { \ + auto pos = mBinding.get()->isInSelectedRows(i); \ + if (pos > 0) { \ + result.emplace_back(mBinding.get()->iteratorAt(pos)); \ + } \ + } \ + return result; \ + } else { \ + static_assert(o2::framework::always_static_assert_v, "T is not a Filtered type"); \ + } \ + return {}; \ + } \ + \ auto _Getter_() const \ { \ return _Getter_##_as(); \ @@ -3078,9 +3090,15 @@ consteval auto getIndexTargets() if (O2_BUILTIN_UNLIKELY(t == nullptr)) { \ o2::soa::dereferenceWithWrongType(#_Getter_, "self"); \ } \ + return getIterators(); \ + } \ + \ + template \ + auto getIterators() const \ + { \ auto result = std::vector(); \ for (auto& i : *mColumnIterator) { \ - result.push_back(t->rawIteratorAt(i)); \ + result.push_back(mBinding.get()->rawIteratorAt(i)); \ } \ return result; \ } \ diff --git a/Framework/Core/include/Framework/AnalysisManagers.h b/Framework/Core/include/Framework/AnalysisManagers.h index 121ce7f4b4a77..fd41a079c6570 100644 --- a/Framework/Core/include/Framework/AnalysisManagers.h +++ b/Framework/Core/include/Framework/AnalysisManagers.h @@ -534,6 +534,12 @@ void bindExternalIndicesPartition(P& partition, T*... tables) } /// Cache handling +template +bool preInitializeCache(InitContext&, T&) +{ + return false; +} + template bool initializeCache(ProcessingContext&, T&) { diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index 365c6b1d41692..4f8a9e719e4b9 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -22,6 +22,7 @@ #include "Framework/EndOfStreamContext.h" #include "Framework/GroupSlicer.h" #include "Framework/StructToTuple.h" +#include "Framework/Traits.h" #include "Framework/TypeIdHelpers.h" #include "Framework/ArrowTableSlicingCache.h" #include "Framework/AnalysisDataModel.h" @@ -62,20 +63,17 @@ static constexpr bool is_enumeration_v> = true; template concept is_enumeration = is_enumeration_v>; -template -concept is_table_iterator_or_enumeration = soa::is_table_or_iterator || is_enumeration; - // Helper struct which builds a DataProcessorSpec from // the contents of an AnalysisTask... namespace { struct AnalysisDataProcessorBuilder { - template + template static void addGroupingCandidates(Cache& bk, Cache& bku, bool enabled) { - [](framework::pack, Cache& bk, Cache& bku, bool enabled) { + [&bk, &bku, enabled](framework::pack) mutable { auto key = std::string{"fIndex"} + o2::framework::cutString(soa::getLabelFromType>()); - ([](Cache& bk, Cache& bku, bool enabled, std::string const& key) { + ([&bk, &bku, &key, enabled]() mutable { if constexpr (soa::relatedByIndex, std::decay_t>()) { Entry e{soa::getLabelFromTypeForKey>(key), soa::getMatcherFromTypeForKey>(key), key, enabled}; if constexpr (o2::soa::is_smallgroups>) { @@ -84,9 +82,9 @@ struct AnalysisDataProcessorBuilder { framework::updatePairList(bk, e); } } - }(bk, bku, enabled, key), + }(), ...); - }(framework::pack{}, bk, bku, enabled); + }(framework::pack{}); } template @@ -170,8 +168,8 @@ struct AnalysisDataProcessorBuilder { return true; } /// 1. enumeration (must be the only argument) - template - static void inputsFromArgs(void (C::*)(A), const char* /*name*/, bool /*value*/, std::vector& inputs, std::vector&) //, Cache&, Cache&) + template + static void inputsFromArgs(R (C::*)(A), const char* /*name*/, bool /*value*/, std::vector& inputs, std::vector&) //, Cache&, Cache&) { std::vector inputMetadata; // FIXME: for the moment we do not support begin, end and step. @@ -179,37 +177,37 @@ struct AnalysisDataProcessorBuilder { } /// 2. 1st argument is an iterator - template - static void inputsFromArgs(void (C::*)(A, Args...), const char* name, bool value, std::vector& inputs, std::vector& eInfos) //, Cache& bk, Cache& bku) + template + static void inputsFromArgs(R (C::*)(A, Args...), const char* name, bool value, std::vector& inputs, std::vector& eInfos) //, Cache& bk, Cache& bku) requires(std::is_lvalue_reference_v && (std::is_lvalue_reference_v && ...)) { - constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); + constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); addInputsAndExpressions::parent_t, Args...>(hash, name, value, inputs, eInfos); } /// 3. generic case - template - static void inputsFromArgs(void (C::*)(Args...), const char* name, bool value, std::vector& inputs, std::vector& eInfos) //, Cache&, Cache&) + template + static void inputsFromArgs(R (C::*)(Args...), const char* name, bool value, std::vector& inputs, std::vector& eInfos) //, Cache&, Cache&) requires(std::is_lvalue_reference_v && ...) { - constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); + constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); addInputsAndExpressions(hash, name, value, inputs, eInfos); } /// 1. enumeration (no grouping) - template - static void cacheFromArgs(void (C::*)(A), bool, Cache&, Cache&) + template + static void cacheFromArgs(R (C::*)(A), bool, Cache&, Cache&) { } /// 2. iterator (the only grouping case) - template - static void cacheFromArgs(void (C::*)(A, Args...), bool value, Cache& bk, Cache& bku) + template + static void cacheFromArgs(R (C::*)(A, Args...), bool value, Cache& bk, Cache& bku) { addGroupingCandidates(bk, bku, value); } /// 3. generic case (no grouping) - template - static void cacheFromArgs(void (C::*)(A, Args...), bool, Cache&, Cache&) + template + static void cacheFromArgs(R (C::*)(A, Args...), bool, Cache&, Cache&) { } @@ -284,53 +282,51 @@ struct AnalysisDataProcessorBuilder { } } - template - static auto bindGroupingTable(InputRecord& record, void (C::*)(Grouping, Args...), std::vector& infos) + template + static auto bindGroupingTable(InputRecord& record, R (C::*)(Grouping, Args...), std::vector& infos) requires(!std::same_as) { - constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); + constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); return extract, 0>(record, infos, hash); } - template - static auto bindAssociatedTables(InputRecord& record, void (C::*)(Grouping, Args...), std::vector& infos) + template + static auto bindAssociatedTables(InputRecord& record, R (C::*)(Grouping, Args...), std::vector& infos) requires(!std::same_as && sizeof...(Args) > 0) { constexpr auto p = pack{}; - constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); + constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); return std::make_tuple(extract, has_type_at_v(p) + 1>(record, infos, hash)...); } - template + template static void overwriteInternalIndices(std::tuple& dest, std::tuple const& src) { (std::get(dest).bindInternalIndicesTo(&std::get(src)), ...); } - template - static void invokeProcess(Task& task, InputRecord& inputs, void (Task::*processingFunction)(Grouping, Associated...), std::vector& infos, ArrowTableSlicingCache& slices) + template + static void invokeProcess(Task& task, InputRecord& inputs, R (C::*processingFunction)(Grouping, Associated...), std::vector& infos, ArrowTableSlicingCache& slices) { using G = std::decay_t; auto groupingTable = AnalysisDataProcessorBuilder::bindGroupingTable(inputs, processingFunction, infos); - constexpr const int numElements = nested_brace_constructible_size>() / 10; - // set filtered tables for partitions with grouping - homogeneous_apply_refs_sized([&groupingTable](auto& element) { + homogeneous_apply_refs([&groupingTable](auto& element) { analysis_task_parsers::setPartition(element, groupingTable); analysis_task_parsers::bindInternalIndicesPartition(element, &groupingTable); return true; }, - task); + task); if constexpr (sizeof...(Associated) == 0) { // single argument to process - homogeneous_apply_refs_sized([&groupingTable](auto& element) { + homogeneous_apply_refs([&groupingTable](auto& element) { analysis_task_parsers::bindExternalIndicesPartition(element, &groupingTable); analysis_task_parsers::setGroupedCombination(element, groupingTable); return true; }, - task); + task); if constexpr (soa::is_iterator) { for (auto& element : groupingTable) { std::invoke(processingFunction, task, *element); @@ -348,7 +344,7 @@ struct AnalysisDataProcessorBuilder { // pre-bind self indices std::apply( [&task](auto&... t) mutable { - (homogeneous_apply_refs_sized( + (homogeneous_apply_refs( [&t](auto& p) { analysis_task_parsers::bindInternalIndicesPartition(p, &t); return true; @@ -360,12 +356,12 @@ struct AnalysisDataProcessorBuilder { auto binder = [&task, &groupingTable, &associatedTables](auto& x) mutable { x.bindExternalIndices(&groupingTable, &std::get>(associatedTables)...); - homogeneous_apply_refs_sized([&x](auto& t) mutable { + homogeneous_apply_refs([&x](auto& t) mutable { analysis_task_parsers::setPartition(t, x); analysis_task_parsers::bindExternalIndicesPartition(t, &x); return true; }, - task); + task); }; groupingTable.bindExternalIndices(&std::get>(associatedTables)...); @@ -377,11 +373,11 @@ struct AnalysisDataProcessorBuilder { associatedTables); // GroupedCombinations bound separately, as they should be set once for all associated tables - homogeneous_apply_refs_sized([&groupingTable, &associatedTables](auto& t) { + homogeneous_apply_refs([&groupingTable, &associatedTables](auto& t) { analysis_task_parsers::setGroupedCombination(t, groupingTable, associatedTables); return true; }, - task); + task); overwriteInternalIndices(associatedTables, associatedTables); if constexpr (soa::is_iterator>) { auto slicer = GroupSlicer(groupingTable, associatedTables, slices); @@ -395,28 +391,28 @@ struct AnalysisDataProcessorBuilder { associatedSlices); // bind partitions and grouping table - homogeneous_apply_refs_sized([&groupingTable](auto& x) { + homogeneous_apply_refs([&groupingTable](auto& x) { analysis_task_parsers::bindExternalIndicesPartition(x, &groupingTable); return true; }, - task); + task); invokeProcessWithArgs(task, processingFunction, slice.groupingElement(), associatedSlices); } } else { // bind partitions and grouping table - homogeneous_apply_refs_sized([&groupingTable](auto& x) { + homogeneous_apply_refs([&groupingTable](auto& x) { analysis_task_parsers::bindExternalIndicesPartition(x, &groupingTable); return true; }, - task); + task); invokeProcessWithArgs(task, processingFunction, groupingTable, associatedTables); } } } - template + template static void invokeProcessWithArgs(C& task, T processingFunction, G g, std::tuple& at) { std::invoke(processingFunction, task, g, std::get(at)...); @@ -524,18 +520,16 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) std::vector options; std::vector expressionInfos; - constexpr const int numElements = nested_brace_constructible_size>() / 10; - /// make sure options and configurables are set before expression infos are created - homogeneous_apply_refs_sized([&options](auto& element) { return analysis_task_parsers::appendOption(options, element); }, *task.get()); + homogeneous_apply_refs([&options](auto& element) { return analysis_task_parsers::appendOption(options, element); }, *task.get()); /// extract conditions and append them as inputs - homogeneous_apply_refs_sized([&inputs](auto& element) { return analysis_task_parsers::appendCondition(inputs, element); }, *task.get()); + homogeneous_apply_refs([&inputs](auto& element) { return analysis_task_parsers::appendCondition(inputs, element); }, *task.get()); /// parse process functions defined by corresponding configurables if constexpr (requires { &T::process; }) { AnalysisDataProcessorBuilder::inputsFromArgs(&T::process, "default", true, inputs, expressionInfos); } - homogeneous_apply_refs_sized( + homogeneous_apply_refs( [name = name_str, &expressionInfos, &inputs](auto& x) mutable { // this pushes (argumentIndex, processHash, schemaPtr, nullptr) into expressionInfos for arguments that are Filtered/filtered_iterators return AnalysisDataProcessorBuilder::requestInputsFromArgs(x, name, inputs, expressionInfos); @@ -544,39 +538,39 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) // request base tables for spawnable extended tables and indices to be built // this checks for duplications - homogeneous_apply_refs_sized([&inputs](auto& element) { + homogeneous_apply_refs([&inputs](auto& element) { return analysis_task_parsers::requestInputs(inputs, element); }, - *task.get()); + *task.get()); // no static way to check if the task defines any processing, we can only make sure it subscribes to at least something if (inputs.empty() == true) { LOG(warn) << "Task " << name_str << " has no inputs"; } - homogeneous_apply_refs_sized([&outputs, &hash](auto& element) { return analysis_task_parsers::appendOutput(outputs, element, hash); }, *task.get()); + homogeneous_apply_refs([&outputs, &hash](auto& element) { return analysis_task_parsers::appendOutput(outputs, element, hash); }, *task.get()); auto requiredServices = CommonServices::defaultServices(); auto arrowServices = CommonServices::arrowServices(); requiredServices.insert(requiredServices.end(), arrowServices.begin(), arrowServices.end()); - homogeneous_apply_refs_sized([&requiredServices](auto& element) { return analysis_task_parsers::addService(requiredServices, element); }, *task.get()); + homogeneous_apply_refs([&requiredServices](auto& element) { return analysis_task_parsers::addService(requiredServices, element); }, *task.get()); auto algo = AlgorithmSpec::InitCallback{[task = task, expressionInfos](InitContext& ic) mutable { Cache bindingsKeys; Cache bindingsKeysUnsorted; // add preslice declarations to slicing cache definition - homogeneous_apply_refs_sized([&bindingsKeys, &bindingsKeysUnsorted](auto& element) { return analysis_task_parsers::registerCache(element, bindingsKeys, bindingsKeysUnsorted); }, *task.get()); + homogeneous_apply_refs([&bindingsKeys, &bindingsKeysUnsorted](auto& element) { return analysis_task_parsers::registerCache(element, bindingsKeys, bindingsKeysUnsorted); }, *task.get()); - homogeneous_apply_refs_sized([&ic](auto&& element) { return analysis_task_parsers::prepareOption(ic, element); }, *task.get()); - homogeneous_apply_refs_sized([&ic](auto&& element) { return analysis_task_parsers::prepareService(ic, element); }, *task.get()); + homogeneous_apply_refs([&ic](auto&& element) { return analysis_task_parsers::prepareOption(ic, element); }, *task.get()); + homogeneous_apply_refs([&ic](auto&& element) { return analysis_task_parsers::prepareService(ic, element); }, *task.get()); auto& callbacks = ic.services().get(); auto eoscb = [task](EndOfStreamContext& eosContext) { - homogeneous_apply_refs_sized([&eosContext](auto& element) { + homogeneous_apply_refs([&eosContext](auto& element) { analysis_task_parsers::postRunService(eosContext, element); analysis_task_parsers::postRunOutput(eosContext, element); return true; }, - *task.get()); + *task.get()); eosContext.services().get().readyToQuit(QuitRequest::Me); }; @@ -588,75 +582,84 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) } /// update configurables in filters and partitions - homogeneous_apply_refs_sized( + homogeneous_apply_refs( [&ic](auto& element) -> bool { return analysis_task_parsers::updatePlaceholders(ic, element); }, *task.get()); /// create expression trees for filters gandiva trees matched to schemas and store the pointers into expressionInfos - homogeneous_apply_refs_sized([&expressionInfos](auto& element) { + homogeneous_apply_refs([&expressionInfos](auto& element) { return analysis_task_parsers::createExpressionTrees(expressionInfos, element); }, - *task.get()); + *task.get()); /// parse process functions to enable requested grouping caches - note that at this state process configurables have their final values if constexpr (requires { &T::process; }) { AnalysisDataProcessorBuilder::cacheFromArgs(&T::process, true, bindingsKeys, bindingsKeysUnsorted); } - homogeneous_apply_refs_sized( - [&bindingsKeys, &bindingsKeysUnsorted](auto& x) { + homogeneous_apply_refs( + [&bindingsKeys, &bindingsKeysUnsorted](auto& x) mutable { return AnalysisDataProcessorBuilder::requestCacheFromArgs(x, bindingsKeys, bindingsKeysUnsorted); }, *task.get()); ic.services().get().setCaches(std::move(bindingsKeys)); ic.services().get().setCachesUnsorted(std::move(bindingsKeysUnsorted)); + // initialize global caches + homogeneous_apply_refs([&ic](auto& element) { + return analysis_task_parsers::preInitializeCache(ic, element); + }, + *(task.get())); return [task, expressionInfos](ProcessingContext& pc) mutable { // load the ccdb object from their cache - homogeneous_apply_refs_sized([&pc](auto& element) { return analysis_task_parsers::newDataframeCondition(pc.inputs(), element); }, *task.get()); + homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::newDataframeCondition(pc.inputs(), element); }, *task.get()); // reset partitions once per dataframe - homogeneous_apply_refs_sized([](auto& element) { return analysis_task_parsers::newDataframePartition(element); }, *task.get()); + homogeneous_apply_refs([](auto& element) { return analysis_task_parsers::newDataframePartition(element); }, *task.get()); // reset selections for the next dataframe - std::ranges::for_each(expressionInfos, [](auto& info) { info.resetSelection = true; }); + for (auto& info : expressionInfos) { + info.resetSelection = true; + } // reset pre-slice for the next dataframe auto slices = pc.services().get(); - homogeneous_apply_refs_sized([&slices](auto& element) { + homogeneous_apply_refs([&slices](auto& element) { return analysis_task_parsers::updateSliceInfo(element, slices); }, - *(task.get())); + *(task.get())); // initialize local caches - homogeneous_apply_refs_sized([&pc](auto& element) { return analysis_task_parsers::initializeCache(pc, element); }, *(task.get())); + homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::initializeCache(pc, element); }, *(task.get())); // prepare outputs - homogeneous_apply_refs_sized([&pc](auto& element) { return analysis_task_parsers::prepareOutput(pc, element); }, *task.get()); + homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::prepareOutput(pc, element); }, *task.get()); // execute run() if constexpr (requires { task->run(pc); }) { task->run(pc); } // execute process() - if constexpr (requires { &T::process; }) { + if constexpr (requires { AnalysisDataProcessorBuilder::invokeProcess(*(task.get()), pc.inputs(), &T::process, expressionInfos, slices); }) { AnalysisDataProcessorBuilder::invokeProcess(*(task.get()), pc.inputs(), &T::process, expressionInfos, slices); } // execute optional process() - homogeneous_apply_refs_sized( - [&pc, &expressionInfos, &task, &slices](auto& x) { - if constexpr (is_process_configurable) { + homogeneous_apply_refs( + [&pc, &expressionInfos, &task, &slices](auto& x) mutable { + if constexpr (base_of_template>) { if (x.value == true) { AnalysisDataProcessorBuilder::invokeProcess(*task.get(), pc.inputs(), x.process, expressionInfos, slices); return true; } - return false; } return false; }, *task.get()); // prepare delayed outputs - homogeneous_apply_refs_sized([&pc](auto& element) { return analysis_task_parsers::prepareDelayedOutput(pc, element); }, *task.get()); + homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::prepareDelayedOutput(pc, element); }, *task.get()); // finalize outputs - homogeneous_apply_refs_sized([&pc](auto& element) { return analysis_task_parsers::finalizeOutput(pc, element); }, *task.get()); + homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::finalizeOutput(pc, element); }, *task.get()); }; }}; return { name, + // FIXME: For the moment we hardcode this. We could build + // this list from the list of methods actually implemented in the + // task itself. inputs, outputs, algo, diff --git a/Framework/Foundation/include/Framework/StructToTuple.h b/Framework/Foundation/include/Framework/StructToTuple.h index 1c7aa62260bd3..5748329f6a50d 100644 --- a/Framework/Foundation/include/Framework/StructToTuple.h +++ b/Framework/Foundation/include/Framework/StructToTuple.h @@ -174,9 +174,9 @@ consteval int nested_brace_constructible_size() return brace_constructible_size() - nesting; } -template () / 10, typename L> +template () / 10> requires(D == 9) -constexpr auto homogeneous_apply_refs(L l, T&& object) +auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -194,9 +194,9 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10, typename L> +template () / 10> requires(D == 8) -constexpr auto homogeneous_apply_refs(L l, T&& object) +auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -214,9 +214,9 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10, typename L> +template () / 10> requires(D == 7) -constexpr auto homogeneous_apply_refs(L l, T&& object) +auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -234,9 +234,9 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10, typename L> +template () / 10> requires(D == 6) -constexpr auto homogeneous_apply_refs(L l, T&& object) +auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -254,9 +254,9 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10, typename L> +template () / 10> requires(D == 5) -constexpr auto homogeneous_apply_refs(L l, T&& object) +auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -274,9 +274,9 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10, typename L> +template () / 10> requires(D == 4) -constexpr auto homogeneous_apply_refs(L l, T&& object) +auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -294,9 +294,9 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10, typename L> +template () / 10> requires(D == 3) -constexpr auto homogeneous_apply_refs(L l, T&& object) +auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -314,9 +314,9 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10, typename L> +template () / 10> requires(D == 2) -constexpr auto homogeneous_apply_refs(L l, T&& object) +auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -334,9 +334,9 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10, typename L> +template () / 10> requires(D == 1) -constexpr auto homogeneous_apply_refs(L l, T&& object) +auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -354,9 +354,9 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10, typename L> +template () / 10> requires(D == 0) -constexpr auto homogeneous_apply_refs(L l, T&& object) +auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -373,12 +373,6 @@ constexpr auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template -constexpr auto homogeneous_apply_refs_sized(L l, T&& object) -{ - return homogeneous_apply_refs(l, object); -} - } // namespace o2::framework #endif // O2_FRAMEWORK_STRUCTTOTUPLE_H_ From dd70bca748eca6084e14c34d048c7ad4b79c120b Mon Sep 17 00:00:00 2001 From: Pavel Larionov Date: Fri, 30 Jan 2026 17:02:29 +0100 Subject: [PATCH 137/234] ALICE 3: add fully cylindrical IRIS, correct Si thickness, add v3 building (#14979) * VD layer sensitive silicon 20 um, 80 um non-sens * Add an option for pure cylindrical IRIS * add v3 building option for FT3 * build pure cyl IRIS v3 by default --- .../include/FT3Simulation/Detector.h | 1 + .../ALICE3/FT3/simulation/src/Detector.cxx | 61 +++- .../ALICE3/TRK/base/include/TRKBase/Specs.h | 4 +- .../include/TRKSimulation/VDGeometryBuilder.h | 8 +- .../include/TRKSimulation/VDLayer.h | 13 +- .../ALICE3/TRK/simulation/src/Detector.cxx | 2 +- .../TRK/simulation/src/VDGeometryBuilder.cxx | 307 ++++++++++++++---- .../ALICE3/TRK/simulation/src/VDLayer.cxx | 280 ++++++++++++++-- 8 files changed, 585 insertions(+), 91 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/Detector.h b/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/Detector.h index a88ea5a351ad2..a68f8cf7788b6 100644 --- a/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/Detector.h +++ b/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/Detector.h @@ -116,6 +116,7 @@ class Detector : public o2::base::DetImpl void buildFT3V3b(); void buildFT3Scoping(); void buildFT3NewVacuumVessel(); + void buildFT3ScopingV3(); void buildFT3FromFile(std::string); GeometryTGeo* mGeometryTGeo; //! access to geometry details diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx index aab8ae070d936..9303979ada930 100644 --- a/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx @@ -346,6 +346,65 @@ void Detector::buildFT3NewVacuumVessel() } } +void Detector::buildFT3ScopingV3() +{ + // Build the FT3 detector according to v3 layout + // https://indico.cern.ch/event/1596309/contributions/6728167/attachments/3190117/5677220/2025-12-10-AW-ALICE3planning.pdf + // Middle disks inner radius 10 cm + // Outer disks inner radius 20 cm + + LOG(info) << "Building FT3 Detector: v3 scoping version"; + + mNumberOfLayers = 6; + float sensorThickness = 30.e-4; + float layersx2X0 = 1.e-2; + std::vector> layersConfigCSide{ + {77., 10.0, 35., layersx2X0}, // {z_layer, r_in, r_out, Layerx2X0} + {100., 10.0, 35., layersx2X0}, + {122., 10.0, 35., layersx2X0}, + {150., 20.0, 68.f, layersx2X0}, + {180., 20.0, 68.f, layersx2X0}, + {220., 20.0, 68.f, layersx2X0}}; + + std::vector> layersConfigASide{ + {77., 10.0, 35., layersx2X0}, // {z_layer, r_in, r_out, Layerx2X0} + {100., 10.0, 35., layersx2X0}, + {122., 10.0, 35., layersx2X0}, + {150., 20.0, 68.f, layersx2X0}, + {180., 20.0, 68.f, layersx2X0}, + {220., 20.0, 68.f, layersx2X0}}; + + mLayerName.resize(2); + mLayerName[0].resize(mNumberOfLayers); + mLayerName[1].resize(mNumberOfLayers); + mLayerID.clear(); + mLayers.resize(2); + + for (auto direction : {0, 1}) { + for (int layerNumber = 0; layerNumber < mNumberOfLayers; layerNumber++) { + std::string directionName = std::to_string(direction); + std::string layerName = GeometryTGeo::getFT3LayerPattern() + directionName + std::string("_") + std::to_string(layerNumber); + mLayerName[direction][layerNumber] = layerName; + float z, rIn, rOut, x0; + if (direction == 0) { // C-Side + z = layersConfigCSide[layerNumber][0]; + rIn = layersConfigCSide[layerNumber][1]; + rOut = layersConfigCSide[layerNumber][2]; + x0 = layersConfigCSide[layerNumber][3]; + } else if (direction == 1) { // A-Side + z = layersConfigASide[layerNumber][0]; + rIn = layersConfigASide[layerNumber][1]; + rOut = layersConfigASide[layerNumber][2]; + x0 = layersConfigASide[layerNumber][3]; + } + + LOG(info) << "Adding Layer " << layerName << " at z = " << z; + // Add layers + auto& thisLayer = mLayers[direction].emplace_back(direction, layerNumber, layerName, z, rIn, rOut, x0); + } + } +} + //_________________________________________________________________________________________________ void Detector::buildFT3Scoping() { @@ -411,7 +470,7 @@ Detector::Detector(bool active) } else { switch (ft3BaseParam.geoModel) { case Default: - buildFT3NewVacuumVessel(); // FT3 after Upgrade days March 2024 + buildFT3ScopingV3(); // v3 Dec 25 break; case Telescope: buildBasicFT3(ft3BaseParam); // BasicFT3 = Parametrized telescopic detector (equidistant layers) diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h index 95f9f9b00d7f3..c3c7de9dbe910 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/Specs.h @@ -34,11 +34,11 @@ namespace VD // TODO: add a primitive segmentation with more granularity wrt 1/4 { namespace silicon { -constexpr double thickness{30 * mu}; // thickness of the silicon (should be 10 um epitaxial layer + 20 um substrate)? +constexpr double thickness{20 * mu}; // thickness of the silicon (should be 10 um epitaxial layer + 20 um substrate)? } // namespace silicon namespace metalstack { -constexpr double thickness{0 * mu}; // thickness of the copper metal stack - for the moment it is not implemented +constexpr double thickness{80 * mu}; // thickness of the copper metal stack - for the moment it is not implemented. PL: set to 80 um considering silicon as material } // namespace metalstack namespace petal { diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/VDGeometryBuilder.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/VDGeometryBuilder.h index 0a2cb68f2233a..c337ddb102147 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/VDGeometryBuilder.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/VDGeometryBuilder.h @@ -24,9 +24,11 @@ namespace o2::trk // Each function builds one local petal assembly (walls + layers + disks) // and then places/rotates the petal once into the mother volume. -void createIRIS4Geometry(TGeoVolume* motherVolume); // 4 petals, cylindrical L0 -void createIRIS4aGeometry(TGeoVolume* motherVolume); // 3 petals, cylindrical L0 -void createIRIS5Geometry(TGeoVolume* motherVolume); // 4 petals, rectangular L0 +void createIRISGeometryFullCyl(TGeoVolume* motherVolume); // Full-cylinder IRIS geometry (no petals, no gaps, no side walls) +void createIRISGeometryFullCylwithDisks(TGeoVolume* motherVolume); // Full-cylinder IRIS geometry (no petals, no gaps, no side walls) incl. disks +void createIRIS4Geometry(TGeoVolume* motherVolume); // 4 petals, cylindrical L0 +void createIRIS4aGeometry(TGeoVolume* motherVolume); // 3 petals, cylindrical L0 +void createIRIS5Geometry(TGeoVolume* motherVolume); // 4 petals, rectangular L0 void createSinglePetalDebug(TGeoVolume* motherVolume, int petalID = 0, int nPetals = 4, bool rectangularL0 = false); diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/VDLayer.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/VDLayer.h index 9e9ca2971bc3b..acf9b19342e4b 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/VDLayer.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/VDLayer.h @@ -39,9 +39,10 @@ class VDLayer protected: int mLayerNumber{0}; std::string mLayerName; - double mX2X0{0.f}; // Radiation length in units of X0 - double mChipThickness{0.f}; // thickness derived from X/X0 - double mModuleWidth{4.54f}; // cm + double mX2X0{0.f}; // Radiation length in units of X0 + double mChipThickness{0.f}; // thickness derived from X/X0 + double mSensorThickness{0.f}; // + double mModuleWidth{4.54f}; // cm // ClassDef(VDLayer, 1) }; @@ -54,6 +55,8 @@ class VDCylindricalLayer : public VDLayer double radius, double phiSpanDeg, double lengthZ, double lengthSensZ); TGeoVolume* createSensor() const; // builds the sensor volume + TGeoVolume* createChip() const; + TGeoVolume* createMetalStack() const; void createLayer(TGeoVolume* motherVolume, TGeoMatrix* combiTrans = nullptr) const override; private: @@ -73,6 +76,8 @@ class VDRectangularLayer : public VDLayer double width, double lengthZ, double lengthSensZ); TGeoVolume* createSensor() const; + TGeoVolume* createChip() const; + TGeoVolume* createMetalStack() const; void createLayer(TGeoVolume* motherVolume, TGeoMatrix* combiTrans = nullptr) const override; private: @@ -91,6 +96,8 @@ class VDDiskLayer : public VDLayer double rMin, double rMax, double phiSpanDeg, double zPos); TGeoVolume* createSensor() const; + TGeoVolume* createChip() const; + TGeoVolume* createMetalStack() const; void createLayer(TGeoVolume* motherVolume, TGeoMatrix* combiTrans = nullptr) const override; double getZPosition() const { return mZPos; } diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx index 0924be5fb6764..e0fc6ef1ed35b 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx @@ -266,7 +266,7 @@ void Detector::createGeometry() // Alternatives: createIRIS5Geometry(vTRK); createIRIS4aGeometry(vTRK); o2::trk::clearVDSensorRegistry(); - o2::trk::createIRIS4Geometry(vTRK); + o2::trk::createIRISGeometryFullCyl(vTRK); // Fill sensor names from registry right after geometry creation const auto& regs = o2::trk::vdSensorRegistry(); diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/VDGeometryBuilder.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/VDGeometryBuilder.cxx index 5df875713262c..6ce04bb8443ef 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/VDGeometryBuilder.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/VDGeometryBuilder.cxx @@ -67,6 +67,12 @@ inline bool isSolidToCut(const TGeoVolume* v) if (TString(nm).BeginsWith("VD_SideWall")) { return true; } + if (TString(nm).BeginsWith("VD_InnerWallCyl")) { + return true; + } + if (TString(nm).BeginsWith("VD_OuterWallCyl")) { + return true; + } if (TString(nm).Contains("_Coldplate")) { return true; } @@ -166,7 +172,34 @@ inline void buildPetalSolidsComposite(TGeoVolume* petalAsm) // Build the global cutout by rotating the petal-local composite n times with (p+0.5) phase inline void buildIrisCutoutFromPetalSolid(int nPetals) { - // Create n rotation transforms + auto* shps = gGeoManager->GetListOfShapes(); + auto* base = shps ? dynamic_cast(shps->FindObject("IRIS_PETAL_SOLIDSsh")) : nullptr; + if (!base) { + LOGP(error, "IRIS cutout: shape 'IRIS_PETAL_SOLIDSsh' not found."); + return; + } + + // IMPORTANT: for nPetals==1, a composite expression like "A:tr" is invalid. + // Just clone the petal solids shape as the global cutout. + if (nPetals == 1) { + // Remove any previous shape with same name if it exists (optional but keeps things clean) + if (shps->FindObject("IRIS_CUTOUTsh")) { + // ROOT shape lists are owned by gGeoManager; removing is not always necessary. + // Keeping it simple: just create a unique name if it already exists. + LOGP(warning, "IRIS cutout: 'IRIS_CUTOUTsh' already exists; overwriting by clone name reuse may be unsafe."); + } + + auto* cut = dynamic_cast(base->Clone("IRIS_CUTOUTsh")); + if (!cut) { + LOGP(error, "IRIS cutout: failed to clone 'IRIS_PETAL_SOLIDSsh' to 'IRIS_CUTOUTsh'."); + return; + } + + LOGP(info, "IRIS_CUTOUTsh created as clone of IRIS_PETAL_SOLIDSsh (nPetals=1)."); + return; + } + + // nPetals > 1: build union of rotated copies TString cutFormula; for (int p = 0; p < nPetals; ++p) { const double phi = (360.0 / nPetals) * (p + 0.5); @@ -175,47 +208,23 @@ inline void buildIrisCutoutFromPetalSolid(int nPetals) auto* RT = new TGeoCombiTrans(0, 0, 0, R); RT->SetName(Form("IRIS_PETAL_ROT_%d", p)); RT->RegisterYourself(); + if (p) { cutFormula += "+"; } cutFormula += Form("IRIS_PETAL_SOLIDSsh:%s", RT->GetName()); } - LOGP(info, "IRIS_CUTOUTsh formula: {}", cutFormula.Data()); - new TGeoCompositeShape("IRIS_CUTOUTsh", cutFormula.Data()); - // --- Sanity check: required matrices & shapes exist - auto* mats = gGeoManager ? gGeoManager->GetListOfMatrices() : nullptr; - auto* shps = gGeoManager ? gGeoManager->GetListOfShapes() : nullptr; + LOGP(info, "IRIS_CUTOUTsh formula: {}", cutFormula.Data()); + auto* cut = new TGeoCompositeShape("IRIS_CUTOUTsh", cutFormula.Data()); + (void)cut; - if (!mats || !shps) { - LOGP(error, "IRIS cutout sanity: gGeoManager not initialized properly (mats/shapes missing)."); + // Stronger sanity: ensure it parsed into a boolean node + auto* cutCheck = dynamic_cast(shps->FindObject("IRIS_CUTOUTsh")); + if (!cutCheck || !cutCheck->GetBoolNode()) { + LOGP(error, "IRIS cutout sanity: IRIS_CUTOUTsh exists but parsing failed (no BoolNode)."); } else { - bool ok = true; - - // Check the petal rotations were registered and referenced - for (int p = 0; p < nPetals; ++p) { - const TString name = Form("IRIS_PETAL_ROT_%d", p); - if (!mats->FindObject(name)) { - LOGP(error, "IRIS cutout sanity: missing matrix {}", name.Data()); - ok = false; - } - } - - // Check that the local petal composite exists - if (!shps->FindObject("IRIS_PETAL_SOLIDSsh")) { - LOGP(error, "IRIS cutout sanity: shape 'IRIS_PETAL_SOLIDSsh' not found."); - ok = false; - } - - // Check that the global cutout shape was created - if (!shps->FindObject("IRIS_CUTOUTsh")) { - LOGP(error, "IRIS cutout sanity: shape 'IRIS_CUTOUTsh' not found."); - ok = false; - } - - if (ok) { - LOGP(info, "IRIS cutout sanity: OK ({} petals).", nPetals); - } + LOGP(info, "IRIS cutout sanity: OK ({} petals).", nPetals); } } @@ -299,7 +308,11 @@ inline TGeoCombiTrans rotZ(double phiDeg) // ============ Petal sub-builders (LOCAL coords only, no rotation) ========= // Walls: inner cylindrical arc at r=4.8 mm (always), outer arc wall, and two side plates. -static void addPetalWalls(TGeoVolume* petalAsm, int nPetals, double outerRadius_cm = kOuterWallRadius_cm) +static void addPetalWalls(TGeoVolume* petalAsm, + int nPetals, + double outerRadius_cm = kOuterWallRadius_cm, + bool withSideWalls = true, + bool fullCylindricalRadialWalls = false) { if (!petalAsm) { LOGP(error, "addPetalWalls: petalAsm is null"); @@ -314,11 +327,21 @@ static void addPetalWalls(TGeoVolume* petalAsm, int nPetals, double outerRadius_ return; } - const double halfPhi = 0.5f * (360.f / static_cast(nPetals)); - const double halfZ = 0.5f * kPetalZ_cm; + const double halfZ = 0.5 * kPetalZ_cm; - // ---- Inner cylindrical wall (always at r=4.8 mm) ---- - { + // In full-cylinder radial-wall mode we ignore nPetals for the radial walls. + const double halfPhi = fullCylindricalRadialWalls ? 180.0 : 0.5 * (360.0 / static_cast(nPetals)); + + // ---- Inner radial wall ---- + if (fullCylindricalRadialWalls) { + auto* s = new TGeoTube(static_cast(kInnerWallRadius_cm), + static_cast(kInnerWallRadius_cm + kWallThick_cm), + static_cast(halfZ)); + auto* v = new TGeoVolume("VD_InnerWallCyl", s, med); + v->SetLineColor(kGray + 2); + v->SetTransparency(70); + petalAsm->AddNode(v, 1); + } else { auto* s = new TGeoTubeSeg(static_cast(kInnerWallRadius_cm), static_cast(kInnerWallRadius_cm + kWallThick_cm), static_cast(halfZ), @@ -330,8 +353,16 @@ static void addPetalWalls(TGeoVolume* petalAsm, int nPetals, double outerRadius_ petalAsm->AddNode(v, 1); } - // ---- Outer arc wall ---- - { + // ---- Outer radial wall ---- + if (fullCylindricalRadialWalls) { + auto* s = new TGeoTube(static_cast(outerRadius_cm), + static_cast(outerRadius_cm + kWallThick_cm), + static_cast(halfZ)); + auto* v = new TGeoVolume("VD_OuterWallCyl", s, med); + v->SetLineColor(kGray + 2); + v->SetTransparency(70); + petalAsm->AddNode(v, 1); + } else { auto* s = new TGeoTubeSeg(static_cast(outerRadius_cm), static_cast(outerRadius_cm + kWallThick_cm), static_cast(halfZ), @@ -343,6 +374,11 @@ static void addPetalWalls(TGeoVolume* petalAsm, int nPetals, double outerRadius_ petalAsm->AddNode(v, 1); } + // ---- Side plates (skip in "single petal full cylinders" mode) ---- + if (!withSideWalls) { + return; + } + // ---- Side walls (boxes) at ±halfPhi ---- const double radialLen = (outerRadius_cm - (kInnerWallRadius_cm + kWallThick_cm)); auto* sideS = new TGeoBBox(static_cast(0.5f * radialLen), @@ -369,7 +405,7 @@ static void addPetalWalls(TGeoVolume* petalAsm, int nPetals, double outerRadius_ // Build inner layers (L0..L2). L0 may be rectangular (IRIS5) or cylindrical. // φ-spans derive from spec gaps/arc; all local placement (no rotation). -static void addBarrelLayers(TGeoVolume* petalAsm, int nPetals, int petalID, bool rectangularL0) +static void addBarrelLayers(TGeoVolume* petalAsm, int nPetals, int petalID, bool rectangularL0, bool fullCylinders) { if (!petalAsm) { LOGP(error, "addBarrelLayers: petalAsm is null"); @@ -382,15 +418,15 @@ static void addBarrelLayers(TGeoVolume* petalAsm, int nPetals, int petalID, bool constexpr double arcL0_cm = 0.6247f; // 6.247 mm // φ spans - const double phiL0_deg = phiSpanFromGap(nPetals, gapL0_cm, rL0_cm); // L0 gap-defined - const double phiL1_deg = phiSpanFromGap(nPetals, gapL1L2_cm, rL1_cm); // L1 gap-defined - const double phiL2_deg = phiSpanFromGap(nPetals, gapL1L2_cm, rL2_cm); // L2 gap-defined + const double phiL0_deg = fullCylinders ? 360.0 : phiSpanFromGap(nPetals, gapL0_cm, rL0_cm); + const double phiL1_deg = fullCylinders ? 360.0 : phiSpanFromGap(nPetals, gapL1L2_cm, rL1_cm); + const double phiL2_deg = fullCylinders ? 360.0 : phiSpanFromGap(nPetals, gapL1L2_cm, rL2_cm); const std::string nameL0 = std::string(o2::trk::GeometryTGeo::getTRKPetalPattern()) + std::to_string(petalID) + "_" + std::string(o2::trk::GeometryTGeo::getTRKPetalLayerPattern()) + "0"; - if (rectangularL0) { + if (!fullCylinders && rectangularL0) { VDRectangularLayer L0(0, nameL0, kX2X0, kL0RectWidth_cm, kLenZ_cm, kLenZ_cm); @@ -438,7 +474,7 @@ static void addBarrelLayers(TGeoVolume* petalAsm, int nPetals, int petalID, bool } // Build cold plate (cylindrical) in local coordinates, and add it to the petal assembly. -static void addColdPlate(TGeoVolume* petalAsm, int nPetals, int petalId) +static void addColdPlate(TGeoVolume* petalAsm, int nPetals, int petalId, bool fullCylinders = false) { if (!petalAsm) { LOGP(error, "addColdPlate: petalAsm is null"); @@ -455,8 +491,9 @@ static void addColdPlate(TGeoVolume* petalAsm, int nPetals, int petalId) constexpr double gapL1L2_cm = 0.12f; // 1.2 mm // φ spans - const double phiSpanColdplate_deg = phiSpanFromGap(nPetals, gapL1L2_cm, rL2_cm); // L2 gap-defined - const double halfPhiDeg = 0.5f * phiSpanColdplate_deg; + const double phiSpanColdplate_deg = + fullCylinders ? 360.0 : phiSpanFromGap(nPetals, gapL1L2_cm, rL2_cm); // L2 gap-defined in normal mode + const double halfPhiDeg = 0.5 * phiSpanColdplate_deg; const double startPhi = -halfPhiDeg; const double endPhi = +halfPhiDeg; @@ -625,7 +662,7 @@ static void addIRISServiceModulesSegmented(TGeoVolume* petalAsm, int nPetals) // Build disks in local coords: each disk gets only a local Z translation. // φ span from gap at rOut. -static void addDisks(TGeoVolume* petalAsm, int nPetals, int petalID) +static void addDisks(TGeoVolume* petalAsm, int nPetals, int petalID, bool fullCylinders) { if (!petalAsm) { @@ -633,7 +670,7 @@ static void addDisks(TGeoVolume* petalAsm, int nPetals, int petalID) return; } - const double phiDisk_deg = phiSpanFromGap(nPetals, 2 * kWallThick_cm, diskRin_cm); + const double phiDisk_deg = fullCylinders ? 360.0 : phiSpanFromGap(nPetals, 2 * kWallThick_cm, diskRin_cm); for (int i = 0; i < 6; ++i) { const std::string nameD = @@ -651,21 +688,124 @@ static void addDisks(TGeoVolume* petalAsm, int nPetals, int petalID) } } +// Add Z end-cap walls to "close" the petal/cylinder volume at zMin and zMax. +// Implemented as thin rings (TGeoTube) with thickness 'capThick_cm' in Z, +// spanning radii [rIn_cm, rOut_cm]. +static void addPetalEndCaps(TGeoVolume* petalAsm, + int petalId, + double rIn_cm, + double rOut_cm, + double zMin_cm, + double zMax_cm, + double capThick_cm) +{ + if (!petalAsm) { + LOGP(error, "addPetalEndCaps: petalAsm is null"); + return; + } + + auto& matmgr = o2::base::MaterialManager::Instance(); + const TGeoMedium* med = + matmgr.getTGeoMedium("ALICE3_TRKSERVICES_ALUMINIUM5083"); + + if (!med) { + LOGP(warning, + "addPetalEndCaps: ALICE3_TRKSERVICES_ALUMINIUM5083 not found, caps not created."); + return; + } + + const double halfT = 0.5 * capThick_cm; + + auto* sh = new TGeoTube(static_cast(rIn_cm), + static_cast(rOut_cm), + static_cast(halfT)); + + TString vname = Form("Petal%d_ZCap", petalId); + auto* v = new TGeoVolume(vname, sh, med); + v->SetLineColor(kGray + 2); + v->SetTransparency(70); + + auto* trMin = new TGeoTranslation(0.0, 0.0, + static_cast(zMin_cm + halfT)); + auto* trMax = new TGeoTranslation(0.0, 0.0, + static_cast(zMax_cm - halfT)); + + petalAsm->AddNode(v, 1, trMin); + petalAsm->AddNode(v, 2, trMax); +} + // Build one complete petal assembly (walls + L0..L2 + disks) in LOCAL coords. -static TGeoVolume* buildPetalAssembly(int nPetals, int petalID, bool rectangularL0) +static TGeoVolume* buildPetalAssembly(int nPetals, + int petalID, + bool rectangularL0, + bool fullCylinders, + bool withSideWalls) { auto* petalAsm = new TGeoVolumeAssembly(Form("PETAL_%d", petalID)); - addPetalWalls(petalAsm, nPetals, kOuterWallRadius_cm); - // Pass petalID to layers/disks for naming - addBarrelLayers(petalAsm, nPetals, petalID, rectangularL0); - addColdPlate(petalAsm, nPetals, petalID); - addDisks(petalAsm, nPetals, petalID); + // In the special mode: no side walls, but keep radial walls as FULL cylinders. + addPetalWalls(petalAsm, nPetals, kOuterWallRadius_cm, + /*withSideWalls=*/withSideWalls, + /*fullCylindricalRadialWalls=*/fullCylinders); + + addBarrelLayers(petalAsm, nPetals, petalID, rectangularL0, fullCylinders); + addDisks(petalAsm, nPetals, petalID, fullCylinders); + + addColdPlate(petalAsm, nPetals, petalID, /*fullCylinders=*/false); addIRISServiceModulesSegmented(petalAsm, nPetals); return petalAsm; } +static TGeoVolume* buildFullCylAssembly(int petalID, bool withDisks) +{ + // IMPORTANT: keep naming consistent with createIRIS4/5 (PETAL_%d) + auto* petalAsm = new TGeoVolumeAssembly(Form("PETAL_%d", petalID)); + + // Radial walls only: full 360° cylinders, no side plates + addPetalWalls(petalAsm, + /*nPetals=*/1, + /*outerRadius_cm=*/kOuterWallRadius_cm, + /*withSideWalls=*/false, + /*fullCylindricalRadialWalls=*/true); + + // --- Z end-cap walls to close the petal in Z --- + { + const double zMin = -0.5 * kLenZ_cm; + const double zMax = +0.5 * kLenZ_cm; + const double rIn = kInnerWallRadius_cm; + const double rOut = kOuterWallRadius_cm + kWallThick_cm; + + addPetalEndCaps(petalAsm, + petalID, + rIn, + rOut, + zMin, + zMax, + kWallThick_cm); + } + + // Full 360° barrel cylinders + addBarrelLayers(petalAsm, + /*nPetals=*/1, + /*petalID=*/petalID, + /*rectangularL0=*/false, + /*fullCylinders=*/true); + + addColdPlate(petalAsm, 1, petalID, /*fullCylinders=*/true); + addIRISServiceModulesSegmented(petalAsm, /*nPetals=*/1); + + // Optionally add full 360° disks + if (withDisks) { + addDisks(petalAsm, + /*nPetals=*/1, + /*petalID=*/petalID, + /*fullCylinders=*/true); + } + + return petalAsm; +} + // =================== Public entry points =================== void createIRIS4Geometry(TGeoVolume* motherVolume) @@ -679,7 +819,9 @@ void createIRIS4Geometry(TGeoVolume* motherVolume) constexpr int nPetals = 4; for (int p = 0; p < nPetals; ++p) { - auto* petal = buildPetalAssembly(nPetals, p, /*rectangularL0*/ false); + auto* petal = buildPetalAssembly(nPetals, p, /*rectangularL0*/ false, + /*fullCylinders=*/false, + /*withSideWalls=*/true); // Build the petal-local solids composite once from the FIRST petal if (p == 0) { buildPetalSolidsComposite(petal); // <-- captures only SOLIDS in local coords @@ -704,7 +846,9 @@ void createIRIS5Geometry(TGeoVolume* motherVolume) constexpr int nPetals = 4; for (int p = 0; p < nPetals; ++p) { - auto* petal = buildPetalAssembly(nPetals, p, /*rectangularL0*/ true); + auto* petal = buildPetalAssembly(nPetals, p, /*rectangularL0*/ true, + /*fullCylinders=*/false, + /*withSideWalls=*/true); // Build the petal-local solids composite once from the FIRST petal if (p == 0) { buildPetalSolidsComposite(petal); // <-- captures only SOLIDS in local coords @@ -729,7 +873,9 @@ void createIRIS4aGeometry(TGeoVolume* motherVolume) constexpr int nPetals = 3; for (int p = 0; p < nPetals; ++p) { - auto* petal = buildPetalAssembly(nPetals, p, /*rectangularL0*/ false); + auto* petal = buildPetalAssembly(nPetals, p, /*rectangularL0*/ false, + /*fullCylinders=*/false, + /*withSideWalls=*/true); // Build the petal-local solids composite once from the FIRST petal if (p == 0) { buildPetalSolidsComposite(petal); // <-- captures only SOLIDS in local coords @@ -743,9 +889,48 @@ void createIRIS4aGeometry(TGeoVolume* motherVolume) buildIrisCutoutFromPetalSolid(nPetals); } +void createIRISGeometryFullCyl(TGeoVolume* motherVolume) +{ + if (!motherVolume) { + LOGP(error, "createIRISGeometryFullCyl: motherVolume is null"); + return; + } + + clearVDSensorRegistry(); + + constexpr int nPetals = 1; + constexpr int petalID = 0; + + auto* petal = buildFullCylAssembly(petalID, /*withDisks=*/false); + motherVolume->AddNode(petal, 1, nullptr); + + buildPetalSolidsComposite(petal); + buildIrisCutoutFromPetalSolid(nPetals); +} + +void createIRISGeometryFullCylwithDisks(TGeoVolume* motherVolume) +{ + if (!motherVolume) { + LOGP(error, "createIRISGeometryFullCylDisks: motherVolume is null"); + return; + } + + clearVDSensorRegistry(); + + constexpr int nPetals = 1; + constexpr int petalID = 0; + + auto* petal = buildFullCylAssembly(petalID, /*withDisks=*/true); + motherVolume->AddNode(petal, 1, nullptr); + + // Same cutout pipeline as createIRIS4/5: + buildPetalSolidsComposite(petal); + buildIrisCutoutFromPetalSolid(nPetals); +} + void createSinglePetalDebug(TGeoVolume* motherVolume, int petalID, int nPetals, bool rectangularL0) { - auto* petal = buildPetalAssembly(nPetals, petalID, rectangularL0); + auto* petal = buildPetalAssembly(nPetals, petalID, rectangularL0, false, true); // Optionally rotate the petal for display const double phiDeg = (360.f / static_cast(nPetals)) * (static_cast(petalID) + 0.5f); diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/VDLayer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/VDLayer.cxx index 20f36f1f6f4e7..411dd485684b9 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/VDLayer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/VDLayer.cxx @@ -11,6 +11,7 @@ #include "TRKSimulation/VDLayer.h" #include "TRKBase/GeometryTGeo.h" +#include "TRKBase/Specs.h" #include "Framework/Logger.h" @@ -32,6 +33,8 @@ VDLayer::VDLayer(int layerNumber, const std::string& layerName, double layerX2X0 { constexpr double kSiX0_cm = 9.5; // Radiation length of Silicon in cm mChipThickness = mX2X0 * kSiX0_cm; + + mSensorThickness = o2::trk::constants::VD::silicon::thickness; // cm } // VDCylindricalLayer constructor @@ -83,7 +86,7 @@ TGeoVolume* VDCylindricalLayer::createSensor() const } std::string sensName = Form("%s_%s%d", this->mLayerName.c_str(), GeometryTGeo::getTRKSensorPattern(), this->mLayerNumber); const double rIn = mRadius; - const double rOut = mRadius + mChipThickness; + const double rOut = mRadius + mSensorThickness; const double halfZ = 0.5 * mLengthSensZ; const double halfPhi = 0.5 * mPhiSpanDeg; // degrees auto* shape = new TGeoTubeSeg(rIn, rOut, halfZ, -halfPhi, +halfPhi); @@ -106,8 +109,8 @@ TGeoVolume* VDRectangularLayer::createSensor() const } std::string sensName = Form("%s_%s%d", this->mLayerName.c_str(), GeometryTGeo::getTRKSensorPattern(), this->mLayerNumber); const double hx = 0.5 * mWidth; - const double hy = 0.5 * mChipThickness; // thickness in Y - const double hz = 0.5 * mLengthSensZ; // <-- use sensor Z length, not full layer + const double hy = 0.5 * mSensorThickness; + const double hz = 0.5 * mLengthSensZ; // <-- use sensor Z length, not full layer auto* shape = new TGeoBBox(hx, hy, hz); auto* vol = new TGeoVolume(sensName.c_str(), shape, medSi); @@ -134,8 +137,8 @@ TGeoVolume* VDDiskLayer::createSensor() const return nullptr; } std::string sensName = Form("%s_%s%d", this->mLayerName.c_str(), GeometryTGeo::getTRKSensorPattern(), this->mLayerNumber); - const double halfThickness = 0.5 * mChipThickness; // disk thickness is along Z - const double halfPhi = 0.5 * mPhiSpanDeg; // degrees + const double halfThickness = 0.5 * mSensorThickness; // active sensor thickness along Z + const double halfPhi = 0.5 * mPhiSpanDeg; // degrees // Same geometry as the layer (identical radii + phi span + thickness) auto* shape = new TGeoTubeSeg(mRMin, mRMax, halfThickness, -halfPhi, +halfPhi); @@ -147,6 +150,243 @@ TGeoVolume* VDDiskLayer::createSensor() const return sensVol; } +/* +** Create metal stack +*/ + +TGeoVolume* VDCylindricalLayer::createMetalStack() const +{ + if (!gGeoManager) { + LOGP(error, "gGeoManager is null"); + return nullptr; + } + auto* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + if (!medSi) { + LOGP(error, "Missing medium TRK_SILICON$"); + return nullptr; + } + + const double metalT = mChipThickness - mSensorThickness; + if (metalT <= 0) { + return nullptr; // nothing to add + } + + std::string name = Form("%s_%s%d", mLayerName.c_str(), + GeometryTGeo::getTRKMetalStackPattern(), mLayerNumber); + + const double rIn = mRadius + mSensorThickness; + const double rOut = mRadius + mChipThickness; + const double halfZ = 0.5 * mLengthSensZ; + const double halfPhi = 0.5 * mPhiSpanDeg; + + auto* shape = new TGeoTubeSeg(rIn, rOut, halfZ, -halfPhi, +halfPhi); + auto* vol = new TGeoVolume(name.c_str(), shape, medSi); + vol->SetLineColor(kGray); + vol->SetTransparency(30); + return vol; +} + +TGeoVolume* VDRectangularLayer::createMetalStack() const +{ + if (!gGeoManager) { + LOGP(error, "gGeoManager is null"); + return nullptr; + } + auto* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + if (!medSi) { + LOGP(error, "Missing medium TRK_SILICON$"); + return nullptr; + } + + const double metalT = mChipThickness - mSensorThickness; + if (metalT <= 0) { + return nullptr; + } + + std::string name = Form("%s_%s%d", mLayerName.c_str(), + GeometryTGeo::getTRKMetalStackPattern(), mLayerNumber); + + const double hx = 0.5 * mWidth; + const double hy = 0.5 * metalT; + const double hz = 0.5 * mLengthSensZ; + + auto* shape = new TGeoBBox(hx, hy, hz); + auto* vol = new TGeoVolume(name.c_str(), shape, medSi); + vol->SetLineColor(kGray); + vol->SetTransparency(30); + return vol; +} + +TGeoVolume* VDDiskLayer::createMetalStack() const +{ + if (!gGeoManager) { + LOGP(error, "gGeoManager is null"); + return nullptr; + } + TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + if (!medSi) { + LOGP(error, "Missing medium TRK_SILICON$"); + return nullptr; + } + + const double metalT = mChipThickness - mSensorThickness; + if (metalT <= 0) { + return nullptr; + } + + if (mRMin < 0 || mRMax <= mRMin || mPhiSpanDeg <= 0 || mPhiSpanDeg > 360.0) { + LOGP(error, "Invalid disk metal dims: rMin={}, rMax={}, metalT={}, phiSpanDeg={}", + mRMin, mRMax, metalT, mPhiSpanDeg); + return nullptr; + } + + std::string name = Form("%s_%s%d", mLayerName.c_str(), + GeometryTGeo::getTRKMetalStackPattern(), mLayerNumber); + + const double halfThickness = 0.5 * metalT; + const double halfPhi = 0.5 * mPhiSpanDeg; + + auto* shape = new TGeoTubeSeg(mRMin, mRMax, halfThickness, -halfPhi, +halfPhi); + auto* vol = new TGeoVolume(name.c_str(), shape, medSi); + vol->SetLineColor(kGray); + vol->SetTransparency(30); + return vol; +} + +/* +** Create chip +*/ + +TGeoVolume* VDCylindricalLayer::createChip() const +{ + if (!gGeoManager) { + LOGP(error, "gGeoManager is null"); + return nullptr; + } + auto* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + if (!medSi) { + LOGP(error, "Missing medium TRK_SILICON$"); + return nullptr; + } + + std::string chipName = Form("%s_%s%d", mLayerName.c_str(), + GeometryTGeo::getTRKChipPattern(), mLayerNumber); + + const double rIn = mRadius; + const double rOut = mRadius + mChipThickness; + const double halfZ = 0.5 * mLengthSensZ; + const double halfPhi = 0.5 * mPhiSpanDeg; + + auto* chipShape = new TGeoTubeSeg(rIn, rOut, halfZ, -halfPhi, +halfPhi); + auto* chipVol = new TGeoVolume(chipName.c_str(), chipShape, medSi); + + // sensor + if (auto* sensVol = createSensor()) { + LOGP(debug, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); + chipVol->AddNode(sensVol, 1, nullptr); + } + + // metal stack + if (auto* metalVol = createMetalStack()) { + LOGP(debug, "Inserting {} in {} ", metalVol->GetName(), chipVol->GetName()); + chipVol->AddNode(metalVol, 1, nullptr); // concentric, no translation needed + } + + chipVol->SetLineColor(kYellow); + chipVol->SetTransparency(30); + return chipVol; +} + +TGeoVolume* VDRectangularLayer::createChip() const +{ + if (!gGeoManager) { + LOGP(error, "gGeoManager is null"); + return nullptr; + } + auto* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + if (!medSi) { + LOGP(error, "Missing medium TRK_SILICON$"); + return nullptr; + } + + std::string chipName = Form("%s_%s%d", mLayerName.c_str(), + GeometryTGeo::getTRKChipPattern(), mLayerNumber); + + const double hx = 0.5 * mWidth; + const double hy = 0.5 * mChipThickness; + const double hz = 0.5 * mLengthSensZ; + + auto* chipShape = new TGeoBBox(hx, hy, hz); + auto* chipVol = new TGeoVolume(chipName.c_str(), chipShape, medSi); + + // sensor (place it on the "bottom" side, like TRK) + if (auto* sensVol = createSensor()) { + auto* transSens = new TGeoTranslation(0.0, -(mChipThickness - mSensorThickness) / 2, 0.0); + LOGP(debug, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); + chipVol->AddNode(sensVol, 1, transSens); + } + + // metal stack (remaining thickness on top) + if (auto* metalVol = createMetalStack()) { + auto* transMetal = new TGeoTranslation(0.0, +mSensorThickness / 2, 0.0); + LOGP(debug, "Inserting {} in {} ", metalVol->GetName(), chipVol->GetName()); + chipVol->AddNode(metalVol, 1, transMetal); + } + + chipVol->SetLineColor(kYellow); + chipVol->SetTransparency(30); + return chipVol; +} + +TGeoVolume* VDDiskLayer::createChip() const +{ + if (!gGeoManager) { + LOGP(error, "gGeoManager is null"); + return nullptr; + } + TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); + if (!medSi) { + LOGP(error, "Missing medium TRK_SILICON$"); + return nullptr; + } + + if (mRMin < 0 || mRMax <= mRMin || mChipThickness <= 0 || + mPhiSpanDeg <= 0 || mPhiSpanDeg > 360.0) { + LOGP(error, "Invalid disk chip dims: rMin={}, rMax={}, t={}, phi={}", + mRMin, mRMax, mChipThickness, mPhiSpanDeg); + return nullptr; + } + + std::string chipName = Form("%s_%s%d", mLayerName.c_str(), + GeometryTGeo::getTRKChipPattern(), mLayerNumber); + + const double halfThickness = 0.5 * mChipThickness; + const double halfPhi = 0.5 * mPhiSpanDeg; + + auto* chipShape = new TGeoTubeSeg(mRMin, mRMax, halfThickness, -halfPhi, +halfPhi); + auto* chipVol = new TGeoVolume(chipName.c_str(), chipShape, medSi); + chipVol->SetLineColor(kYellow); + chipVol->SetTransparency(30); + + // Sensor slab (sensitive) placed on one side in Z (TRK-like stacking convention) + if (auto* sensVol = createSensor()) { + const double zSens = -(mChipThickness - mSensorThickness) / 2.0; + auto* tSens = new TGeoTranslation(0.0, 0.0, zSens); + LOGP(debug, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); + chipVol->AddNode(sensVol, 1, tSens); + } + + // Metal stack slab (non-sensitive), remaining thickness, also silicon + if (auto* metalVol = createMetalStack()) { + const double zMetal = +mSensorThickness / 2.0; + auto* tMetal = new TGeoTranslation(0.0, 0.0, zMetal); + LOGP(debug, "Inserting {} in {} ", metalVol->GetName(), chipVol->GetName()); + chipVol->AddNode(metalVol, 1, tMetal); + } + + return chipVol; +} + /* ** Create layer */ @@ -184,14 +424,14 @@ void VDCylindricalLayer::createLayer(TGeoVolume* motherVolume, TGeoMatrix* combi layerVol->SetLineColor(kYellow); layerVol->SetTransparency(30); - // Sensor volume (must use mLengthSensZ internally) - TGeoVolume* sensorVol = VDCylindricalLayer::createSensor(); - if (!sensorVol) { - LOGP(error, "VDCylindricalLayer::createSensor() returned null"); + // Chip volume (must use mLengthSensZ internally) + TGeoVolume* chipVol = VDCylindricalLayer::createChip(); + if (!chipVol) { + LOGP(error, "VDCylindricalLayer::createChip() returned null"); return; } - LOGP(debug, "Inserting {} in {} ", sensorVol->GetName(), layerVol->GetName()); - layerVol->AddNode(sensorVol, 1, nullptr); + LOGP(debug, "Inserting {} in {} ", chipVol->GetName(), layerVol->GetName()); + layerVol->AddNode(chipVol, 1, nullptr); // Tiling: edge-to-edge if sensor shorter than layer; else single centered // const auto zCenters = (mLengthSensZ < mLengthZ) @@ -238,14 +478,14 @@ void VDRectangularLayer::createLayer(TGeoVolume* motherVolume, TGeoMatrix* combi layerVol->SetTransparency(30); // Sensor volume (uses mLengthSensZ internally) - TGeoVolume* sensorVol = VDRectangularLayer::createSensor(); - if (!sensorVol) { - LOGP(error, "VDRectangularLayer::createSensor() returned null"); + TGeoVolume* chipVol = VDRectangularLayer::createChip(); + if (!chipVol) { + LOGP(error, "VDRectangularLayer::chipVol() returned null"); return; } - LOGP(debug, "Inserting {} in {} ", sensorVol->GetName(), layerVol->GetName()); - layerVol->AddNode(sensorVol, 1, nullptr); + LOGP(debug, "Inserting {} in {} ", chipVol->GetName(), layerVol->GetName()); + layerVol->AddNode(chipVol, 1, nullptr); // Tiling along Z, edge - to - edge if needed // const auto zCenters = (mLengthSensZ < mLengthZ) @@ -292,14 +532,14 @@ void VDDiskLayer::createLayer(TGeoVolume* motherVolume, TGeoMatrix* combiTrans) layerVol->SetTransparency(30); // Sensor (same size & shape as the layer for disks) - TGeoVolume* sensorVol = VDDiskLayer::createSensor(); - if (!sensorVol) { - LOGP(error, "VDDiskLayer::createSensor() returned null"); + TGeoVolume* chipVol = VDDiskLayer::createChip(); + if (!chipVol) { + LOGP(error, "VDDiskLayer::createChip() returned null"); return; } // Insert single sensor (no Z-segmentation for disks) - layerVol->AddNode(sensorVol, 1, nullptr); + layerVol->AddNode(chipVol, 1, nullptr); TGeoTranslation tz(0.0, 0.0, mZPos); motherVolume->AddNode(layerVol, 1, combiTrans ? combiTrans : &tz); From 02a0aebb5718b3faba48c0aad82916e45e93621d Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Sat, 31 Jan 2026 18:59:49 +0100 Subject: [PATCH 138/234] DPL: improve type_to_task_name function (#15006) - Out of line and avoid usage of stringstream. - Remove non-sense abbreviations --- Framework/Core/CMakeLists.txt | 2 + .../Core/include/Framework/AnalysisTask.h | 3 + Framework/Core/src/AnalysisTask.cxx | 77 +++++++++++++++++++ Framework/Core/test/test_TypeToTaskName.cxx | 65 ++++++++++++++++ .../include/Framework/TypeIdHelpers.h | 17 ---- 5 files changed, 147 insertions(+), 17 deletions(-) create mode 100644 Framework/Core/src/AnalysisTask.cxx create mode 100644 Framework/Core/test/test_TypeToTaskName.cxx diff --git a/Framework/Core/CMakeLists.txt b/Framework/Core/CMakeLists.txt index 1daba5dbc9798..7357167a3fcd8 100644 --- a/Framework/Core/CMakeLists.txt +++ b/Framework/Core/CMakeLists.txt @@ -16,6 +16,7 @@ o2_add_library(Framework src/ArrowTableSlicingCache.cxx src/AnalysisDataModel.cxx src/AnalysisSupportHelpers.cxx + src/AnalysisTask.cxx src/ASoA.cxx src/ASoAHelpers.cxx src/AsyncQueue.cxx @@ -254,6 +255,7 @@ add_executable(o2-test-framework-core test/test_TimeParallelPipelining.cxx test/test_TimesliceIndex.cxx test/test_TypeTraits.cxx + test/test_TypeToTaskName.cxx test/test_TopologyPolicies.cxx test/test_Variants.cxx test/test_WorkflowHelpers.cxx diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index 4f8a9e719e4b9..eb98d55cc24b2 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -37,6 +37,9 @@ namespace o2::framework { +/// Convert a CamelCase task struct name to snake-case task name +std::string type_to_task_name(std::string_view const& camelCase); + /// A more familiar task API for the DPL analysis framework. /// This allows you to define your own tasks as subclasses /// of o2::framework::AnalysisTask and to pass them in the specification diff --git a/Framework/Core/src/AnalysisTask.cxx b/Framework/Core/src/AnalysisTask.cxx new file mode 100644 index 0000000000000..e88e6fbc6f041 --- /dev/null +++ b/Framework/Core/src/AnalysisTask.cxx @@ -0,0 +1,77 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include + +namespace o2::framework +{ +/// Convert a CamelCase task struct name to snake-case task name +std::string type_to_task_name(std::string_view const& camelCase) +{ + std::string result; + result.reserve(camelCase.size() * 2 + 2); + + // The first character is always -. + result += "-"; + result += static_cast(std::tolower(camelCase[0])); + + for (auto it = camelCase.begin() + 1; it != camelCase.end(); ++it) { + if (std::isupper(*it) && *(it - 1) != '-') { + result += '-'; + } + result += static_cast(std::tolower(*it)); + } + // Post-process to consolidate common ALICE abbreviations + // Process backwards to handle patterns correctly + static const struct { + std::string_view pattern; + std::string_view replacement; + } abbreviations[] = { + {"-h-m-p-i-d", "-hmpid"}, + {"-e-m-c-a-l", "-emcal"}, + {"-e-m-c", "-emc"}, + {"-i-t-s", "-its"}, + {"-t-p-c", "-tpc"}, + {"-q-c-d", "-qcd"}, + {"-t-o-f", "-tof"}, + {"-t-r-d", "-trd"}, + {"-f-v0", "-fv0"}, + {"-q-a", "-qa"}, + {"-b-c", "-bc"}, + {"-q-c", "-qc"}}; + + std::string consolidated; + consolidated.reserve(result.size()); + + for (int i = result.size() - 1; i >= 0;) { + bool matched = false; + + for (const auto& abbr : abbreviations) { + int startPos = i - abbr.pattern.size() + 1; + if (startPos >= 0 && result.compare(startPos, abbr.pattern.size(), abbr.pattern.data()) == 0) { + consolidated.insert(0, abbr.replacement); + i = startPos - 1; + matched = true; + break; + } + } + + if (!matched) { + consolidated.insert(0, 1, result[i]); + --i; + } + } + if (consolidated[0] == '-') { + return std::string(consolidated.data() + 1); + } + + return consolidated; +} +} // namespace o2::framework diff --git a/Framework/Core/test/test_TypeToTaskName.cxx b/Framework/Core/test/test_TypeToTaskName.cxx new file mode 100644 index 0000000000000..b7b440b13ecfd --- /dev/null +++ b/Framework/Core/test/test_TypeToTaskName.cxx @@ -0,0 +1,65 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include "Framework/AnalysisTask.h" +#include + +using namespace o2::framework; + +TEST_CASE("TypeIdHelpers_BasicConversion") +{ + // Basic CamelCase to snake-case conversion + REQUIRE((type_to_task_name(std::string_view("SimpleTask")) == "simple-task")); + REQUIRE((type_to_task_name(std::string_view("MyTask")) == "my-task")); + REQUIRE((type_to_task_name(std::string_view("Task")) == "task")); +} + +TEST_CASE("TypeIdHelpers_AbbreviationConsolidation") +{ + // Test ALICE detector abbreviations + REQUIRE(type_to_task_name(std::string_view("ITSQA")) == "its-qa"); + REQUIRE(type_to_task_name(std::string_view("TPCQCTask")) == "tpc-qc-task"); + REQUIRE(type_to_task_name(std::string_view("EMCALQATask")) == "emcal-qa-task"); + REQUIRE(type_to_task_name(std::string_view("HMPIDTask")) == "hmpid-task"); + REQUIRE(type_to_task_name(std::string_view("ITSTPCTask")) == "its-tpc-task"); + REQUIRE(type_to_task_name(std::string_view("QCFV0Task")) == "qc-fv0-task"); +} + +TEST_CASE("TypeIdHelpers_QualityControlAbbreviations") +{ + // Test quality control abbreviations + REQUIRE(type_to_task_name(std::string_view("QATask")) == "qa-task"); + REQUIRE(type_to_task_name(std::string_view("QCTask")) == "qc-task"); + REQUIRE(type_to_task_name(std::string_view("QCDAnalysis")) == "qcd-analysis"); +} + +TEST_CASE("TypeIdHelpers_ComplexNames") +{ + // Test complex combinations + REQUIRE(type_to_task_name(std::string_view("ITSQAAnalysisTask")) == "its-qa-analysis-task"); + REQUIRE(type_to_task_name(std::string_view("TPCEMCQCTask")) == "tpc-emc-qc-task"); + REQUIRE(type_to_task_name(std::string_view("MyITSTask")) == "my-its-task"); +} + +TEST_CASE("TypeIdHelpers_EdgeCases") +{ + // Single character + REQUIRE(type_to_task_name(std::string_view("A")) == "a"); + + // All uppercase. BC is Bunch Crossing! + // + REQUIRE(type_to_task_name(std::string_view("ABC")) == "a-bc"); + REQUIRE(type_to_task_name(std::string_view("BC")) == "bc"); + + // Mixed with numbers (numbers are not uppercase, so no hyphens before them) + REQUIRE(type_to_task_name(std::string_view("Task123")) == "task123"); +} diff --git a/Framework/Foundation/include/Framework/TypeIdHelpers.h b/Framework/Foundation/include/Framework/TypeIdHelpers.h index 5eaac2151b909..1dc2464b40ec8 100644 --- a/Framework/Foundation/include/Framework/TypeIdHelpers.h +++ b/Framework/Foundation/include/Framework/TypeIdHelpers.h @@ -13,7 +13,6 @@ #define O2_FRAMEWORK_TYPEIDHELPERS_H_ #include -#include #if __cplusplus >= 202002L #include #endif @@ -82,22 +81,6 @@ struct TypeIdHelpers { } }; -/// Convert a CamelCase task struct name to snake-case task name -inline static std::string type_to_task_name(std::string_view& camelCase) -{ - std::ostringstream str; - str << static_cast(std::tolower(camelCase[0])); - - for (auto it = camelCase.begin() + 1; it != camelCase.end(); ++it) { - if (std::isupper(*it) && *(it - 1) != '-') { - str << "-"; - } - str << static_cast(std::tolower(*it)); - } - - return str.str(); -} - } // namespace o2::framework #endif // O2_FRAMEWORK_TYPEIDHELPERS_H_ From dee4e246302c2a78b02fe2d4b7a29d0f48d2b05f Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Mon, 2 Feb 2026 13:16:21 +0100 Subject: [PATCH 139/234] Revert abbreviations until we get green light from the affected people (#15009) --- Framework/Core/src/AnalysisTask.cxx | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/Framework/Core/src/AnalysisTask.cxx b/Framework/Core/src/AnalysisTask.cxx index e88e6fbc6f041..993c597a95f49 100644 --- a/Framework/Core/src/AnalysisTask.cxx +++ b/Framework/Core/src/AnalysisTask.cxx @@ -34,18 +34,9 @@ std::string type_to_task_name(std::string_view const& camelCase) std::string_view pattern; std::string_view replacement; } abbreviations[] = { - {"-h-m-p-i-d", "-hmpid"}, {"-e-m-c-a-l", "-emcal"}, - {"-e-m-c", "-emc"}, - {"-i-t-s", "-its"}, - {"-t-p-c", "-tpc"}, - {"-q-c-d", "-qcd"}, - {"-t-o-f", "-tof"}, - {"-t-r-d", "-trd"}, - {"-f-v0", "-fv0"}, - {"-q-a", "-qa"}, - {"-b-c", "-bc"}, - {"-q-c", "-qc"}}; + {"-e-m-c", "-emc"} + }; std::string consolidated; consolidated.reserve(result.size()); From 597fc9ee8673ea2bb916c6caf5bbbec8f631a224 Mon Sep 17 00:00:00 2001 From: shahoian Date: Wed, 28 Jan 2026 20:42:39 +0100 Subject: [PATCH 140/234] Leave single implementation of TRD RecoParam, init from GPUSettingsRecTRD --- .../include/Align/AlignableDetectorTRD.h | 4 +- Detectors/Align/src/AlignableDetectorTRD.cxx | 11 +- .../include/SpacePoints/TrackInterpolation.h | 4 +- .../SpacePoints/src/TrackInterpolation.cxx | 4 +- Detectors/TRD/base/CMakeLists.txt | 2 - .../TRD/base/include/TRDBase/RecoParam.h | 64 ----------- Detectors/TRD/base/src/RecoParam.cxx | 64 ----------- Detectors/TRD/base/src/TRDBaseLinkDef.h | 1 - Detectors/TRD/calibration/CMakeLists.txt | 1 + .../include/TRDCalibration/TrackBasedCalib.h | 4 +- .../TRD/calibration/src/TrackBasedCalib.cxx | 5 +- Detectors/TRD/qc/CMakeLists.txt | 1 + Detectors/TRD/qc/include/TRDQC/Tracking.h | 4 +- Detectors/TRD/qc/src/Tracking.cxx | 5 +- .../TRDWorkflow/TRDGlobalTrackingSpec.h | 4 +- .../workflow/src/TRDGlobalTrackingSpec.cxx | 6 +- GPU/GPUTracking/Base/GPUConstantMem.h | 1 - GPU/GPUTracking/CMakeLists.txt | 3 +- GPU/GPUTracking/DataTypes/GPUDataTypesIO.h | 3 +- GPU/GPUTracking/DataTypes/GPUTRDRecoParam.cxx | 100 ++++++++++++++++++ GPU/GPUTracking/DataTypes/GPUTRDRecoParam.h | 84 +++++++++++++++ GPU/GPUTracking/GPUTrackingLinkDef_O2.h | 1 + GPU/GPUTracking/Global/GPUChainTracking.cxx | 13 +++ GPU/GPUTracking/Global/GPUChainTracking.h | 5 + .../Global/GPUChainTrackingGetters.inc | 2 + GPU/GPUTracking/Global/GPUChainTrackingIO.cxx | 10 ++ GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx | 48 ++------- GPU/GPUTracking/TRDTracking/GPUTRDTracker.h | 15 +-- .../TRDTracking/macros/run_trd_tracker.C | 4 +- .../include/GPUWorkflow/GPUWorkflowSpec.h | 3 + GPU/Workflow/src/GPUWorkflowSpec.cxx | 27 +++-- 31 files changed, 286 insertions(+), 217 deletions(-) delete mode 100644 Detectors/TRD/base/include/TRDBase/RecoParam.h delete mode 100644 Detectors/TRD/base/src/RecoParam.cxx create mode 100644 GPU/GPUTracking/DataTypes/GPUTRDRecoParam.cxx create mode 100644 GPU/GPUTracking/DataTypes/GPUTRDRecoParam.h diff --git a/Detectors/Align/include/Align/AlignableDetectorTRD.h b/Detectors/Align/include/Align/AlignableDetectorTRD.h index a73b0f76902d2..4e7577b11055c 100644 --- a/Detectors/Align/include/Align/AlignableDetectorTRD.h +++ b/Detectors/Align/include/Align/AlignableDetectorTRD.h @@ -18,7 +18,7 @@ #define ALIGNABLEDETECTORTRD_H #include "Align/AlignableDetector.h" -#include "TRDBase/RecoParam.h" +#include "GPUTRDRecoParam.h" namespace o2 { @@ -64,7 +64,7 @@ class AlignableDetectorTRD final : public AlignableDetector int processPoints(GIndex gid, int npntCut, bool inv) final; protected: - o2::trd::RecoParam mRecoParam; // parameters required for TRD reconstruction + o2::gpu::GPUTRDRecoParam mRecoParam; // parameters required for TRD reconstruction double mNonRCCorrDzDtgl = 0.; // correction in Z for non-crossing tracklets double mCorrDVT = 0.; // correction to Vdrift*t double mExtraErrRC[2] = {0., 0.}; // extra errors for RC tracklets diff --git a/Detectors/Align/src/AlignableDetectorTRD.cxx b/Detectors/Align/src/AlignableDetectorTRD.cxx index d752553bf6ead..080d0f72b2516 100644 --- a/Detectors/Align/src/AlignableDetectorTRD.cxx +++ b/Detectors/Align/src/AlignableDetectorTRD.cxx @@ -26,6 +26,7 @@ #include "DataFormatsTRD/TrackTRD.h" #include "DataFormatsTRD/Tracklet64.h" #include "DataFormatsTRD/CalibratedTracklet.h" +#include "GPUO2InterfaceConfiguration.h" #include #include @@ -175,10 +176,12 @@ int AlignableDetectorTRD::processPoints(GIndex gid, int npntCut, bool inv) return -1; } auto propagator = o2::base::Propagator::Instance(); // float version! - static float prevBz = -99999.; - if (prevBz != propagator->getNominalBz()) { - prevBz = propagator->getNominalBz(); - mRecoParam.setBfield(prevBz); + static bool firstCall = true; + if (firstCall) { + o2::gpu::GPUO2InterfaceConfiguration config; + config.ReadConfigurableParam(config); + mRecoParam.init(propagator->getNominalBz(), &config.configReconstruction); + firstCall = false; } const auto* transformer = mController->getTRDTransformer(); auto algTrack = mController->getAlgTrack(); diff --git a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h index e7d0fb197ea42..58627250d815e 100644 --- a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h +++ b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h @@ -39,7 +39,7 @@ #include "TPCReconstruction/TPCFastTransformHelperO2.h" #include "DetectorsBase/Propagator.h" #include "DataFormatsGlobalTracking/RecoContainer.h" -#include "TRDBase/RecoParam.h" +#include "GPUTRDRecoParam.h" #include "TRDBase/Geometry.h" class TTree; @@ -441,7 +441,7 @@ class TrackInterpolation std::vector mGIDsSuccess; ///< keep track of the GIDs which could be processed successfully // helpers - o2::trd::RecoParam mRecoParam; ///< parameters required for TRD refit + o2::gpu::GPUTRDRecoParam mRecoParam; ///< parameters required for TRD refit o2::trd::Geometry* mGeoTRD; ///< TRD geometry instance (needed for tilted pad correction) std::unique_ptr mFastTransform{}; ///< TPC cluster transformation float mBz; ///< required for helix approximation diff --git a/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx b/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx index 6c37be9ddc1b1..cd5e3960160a6 100644 --- a/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx +++ b/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx @@ -126,7 +126,9 @@ void TrackInterpolation::init(o2::dataformats::GlobalTrackID::mask_t src, o2::da mFastTransform = std::move(TPCFastTransformHelperO2::instance()->create(0)); mBz = o2::base::Propagator::Instance()->getNominalBz(); - mRecoParam.setBfield(mBz); + o2::gpu::GPUO2InterfaceConfiguration config; + config.ReadConfigurableParam(config); + mRecoParam.init(mBz, &config.configReconstruction); mGeoTRD = o2::trd::Geometry::instance(); mParams = &SpacePointsCalibConfParam::Instance(); diff --git a/Detectors/TRD/base/CMakeLists.txt b/Detectors/TRD/base/CMakeLists.txt index 030fb6cea1e50..e0563a85a3f42 100644 --- a/Detectors/TRD/base/CMakeLists.txt +++ b/Detectors/TRD/base/CMakeLists.txt @@ -16,7 +16,6 @@ o2_add_library(TRDBase src/GeometryFlat.cxx src/PadResponse.cxx src/FeeParam.cxx - src/RecoParam.cxx src/ChamberStatus.cxx src/Calibrations.cxx src/CalOnlineGainTables.cxx @@ -38,7 +37,6 @@ o2_target_root_dictionary(TRDBase include/TRDBase/GeometryFlat.h include/TRDBase/PadResponse.h include/TRDBase/FeeParam.h - include/TRDBase/RecoParam.h include/TRDBase/Calibrations.h include/TRDBase/PadParameters.h include/TRDBase/PadCalibrations.h diff --git a/Detectors/TRD/base/include/TRDBase/RecoParam.h b/Detectors/TRD/base/include/TRDBase/RecoParam.h deleted file mode 100644 index 1828a0b1724e9..0000000000000 --- a/Detectors/TRD/base/include/TRDBase/RecoParam.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file RecoParam.h -/// \brief Error parameterizations and helper functions for TRD reconstruction -/// \author Ole Schmidt - -#ifndef O2_TRD_RECOPARAM_H -#define O2_TRD_RECOPARAM_H - -#include -#include "Rtypes.h" - -namespace o2 -{ -namespace trd -{ - -class RecoParam -{ - public: - RecoParam() = default; - RecoParam(const RecoParam&) = default; - ~RecoParam() = default; - - /// Load parameterization for given magnetic field - void setBfield(float bz); - - /// Recalculate tracklet covariance based on phi angle of related track - void recalcTrkltCov(const float tilt, const float snp, const float rowSize, std::array& cov) const; - - /// Get tracklet r-phi resolution for given phi angle - /// Resolution depends on the track angle sin(phi) = snp and is approximated by the formula - /// sigma_y(snp) = sqrt(a^2 + c^2 * (snp - b^2)^2) - /// more details are given in http://cds.cern.ch/record/2724259 in section 5.3.3 - /// \param phi angle of related track - /// \return sigma_y^2 of tracklet - float getRPhiRes(float snp) const { return (mA2 + mC2 * (snp - mB) * (snp - mB)); } - - /// Get tracklet z correction coefficient for track-eta based corraction - float getZCorrCoeffNRC() const { return mZCorrCoefNRC; } - - private: - // tracklet error parameterization depends on the magnetic field - float mA2{1.f}; ///< parameterization for tracklet position resolution - float mB{0.f}; ///< parameterization for tracklet position resolution - float mC2{0.f}; ///< parameterization for tracklet position resolution - float mZCorrCoefNRC{1.4f}; ///< tracklet z-position depends linearly on track dip angle - - ClassDefNV(RecoParam, 1); -}; - -} // namespace trd -} // namespace o2 - -#endif // O2_TRD_RECOPARAM_H diff --git a/Detectors/TRD/base/src/RecoParam.cxx b/Detectors/TRD/base/src/RecoParam.cxx deleted file mode 100644 index 34921777bdb72..0000000000000 --- a/Detectors/TRD/base/src/RecoParam.cxx +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file RecoParam.cxx -/// \brief Error parameterizations and helper functions for TRD reconstruction -/// \author Ole Schmidt - -#include "TRDBase/RecoParam.h" -#include -#include - -using namespace o2::trd; - -// error parameterizations taken from http://cds.cern.ch/record/2724259 Appendix A -void RecoParam::setBfield(float bz) -{ - if (std::fabs(std::fabs(bz) - 2) < 0.1) { - if (bz > 0) { - // magnetic field +0.2 T - mA2 = 1.6e-3f; - mB = -1.43e-2f; - mC2 = 4.55e-2f; - } else { - // magnetic field -0.2 T - mA2 = 1.6e-3f; - mB = 1.43e-2f; - mC2 = 4.55e-2f; - } - } else if (std::fabs(std::fabs(bz) - 5) < 0.1) { - if (bz > 0) { - // magnetic field +0.5 T - mA2 = 1.6e-3f; - mB = 0.125f; - mC2 = 0.0961f; - } else { - // magnetic field -0.5 T - mA2 = 1.6e-3f; - mB = -0.14f; - mC2 = 0.1156f; - } - } else { - LOG(warning) << "No error parameterization available for Bz= " << bz << ". Keeping default value (sigma_y = const. = 1cm)"; - } - LOG(info) << "Loaded error parameterization for Bz = " << bz; -} - -void RecoParam::recalcTrkltCov(const float tilt, const float snp, const float rowSize, std::array& cov) const -{ - float t2 = tilt * tilt; // tan^2 (tilt) - float c2 = 1.f / (1.f + t2); // cos^2 (tilt) - float sy2 = getRPhiRes(snp); - float sz2 = rowSize * rowSize / 12.f; - cov[0] = c2 * (sy2 + t2 * sz2); - cov[1] = c2 * tilt * (sz2 - sy2); - cov[2] = c2 * (t2 * sy2 + sz2); -} diff --git a/Detectors/TRD/base/src/TRDBaseLinkDef.h b/Detectors/TRD/base/src/TRDBaseLinkDef.h index 2d3de311a1dc0..a835def5628b2 100644 --- a/Detectors/TRD/base/src/TRDBaseLinkDef.h +++ b/Detectors/TRD/base/src/TRDBaseLinkDef.h @@ -19,7 +19,6 @@ #pragma link C++ class o2::trd::Geometry + ; #pragma link C++ class o2::trd::GeometryBase + ; #pragma link C++ class o2::trd::FeeParam + ; -#pragma link C++ class o2::trd::RecoParam + ; #pragma link C++ class o2::trd::PadResponse + ; #pragma link C++ class o2::trd::PadParameters < float > +; #pragma link C++ class o2::trd::PadParameters < char> + ; diff --git a/Detectors/TRD/calibration/CMakeLists.txt b/Detectors/TRD/calibration/CMakeLists.txt index 36d00e92bbc16..52444d2855b1f 100644 --- a/Detectors/TRD/calibration/CMakeLists.txt +++ b/Detectors/TRD/calibration/CMakeLists.txt @@ -28,6 +28,7 @@ o2_add_library(TRDCalibration O2::DetectorsBase O2::DetectorsCalibration O2::MathUtils + O2::GPUTracking O2::DetectorsDCS) o2_target_root_dictionary(TRDCalibration diff --git a/Detectors/TRD/calibration/include/TRDCalibration/TrackBasedCalib.h b/Detectors/TRD/calibration/include/TRDCalibration/TrackBasedCalib.h index 49ba9fdf3d161..7249016d9675e 100644 --- a/Detectors/TRD/calibration/include/TRDCalibration/TrackBasedCalib.h +++ b/Detectors/TRD/calibration/include/TRDCalibration/TrackBasedCalib.h @@ -24,7 +24,7 @@ #include "DataFormatsTRD/NoiseCalibration.h" #include "TRDBase/PadCalibrationsAliases.h" #include "DetectorsBase/Propagator.h" -#include "TRDBase/RecoParam.h" +#include "GPUTRDRecoParam.h" #include "Rtypes.h" @@ -90,7 +90,7 @@ class TrackBasedCalib float mMaxSnp{o2::base::Propagator::MAX_SIN_PHI}; ///< max snp when propagating tracks float mMaxStep{o2::base::Propagator::MAX_STEP}; ///< maximum step for propagation MatCorrType mMatCorr{MatCorrType::USEMatCorrNONE}; ///< if material correction should be done - RecoParam mRecoParam; ///< parameters required for TRD reconstruction + o2::gpu::GPUTRDRecoParam mRecoParam; ///< parameters required for TRD reconstruction AngularResidHistos mAngResHistos; ///< aggregated data for the track based calibration std::vector mGainCalibHistos; ///< aggregated input data for gain calibration float bz; ///< magnetic field diff --git a/Detectors/TRD/calibration/src/TrackBasedCalib.cxx b/Detectors/TRD/calibration/src/TrackBasedCalib.cxx index 011a888a47618..8fe195f861389 100644 --- a/Detectors/TRD/calibration/src/TrackBasedCalib.cxx +++ b/Detectors/TRD/calibration/src/TrackBasedCalib.cxx @@ -13,6 +13,7 @@ /// \brief Provides information required for TRD calibration which is based on the global tracking /// \author Ole Schmidt +#include "GPUO2InterfaceConfiguration.h" #include "TRDCalibration/TrackBasedCalib.h" #include "TRDCalibration/CalibrationParams.h" #include "DataFormatsTRD/Constants.h" @@ -35,7 +36,9 @@ void TrackBasedCalib::reset() void TrackBasedCalib::init() { bz = o2::base::Propagator::Instance()->getNominalBz(); - mRecoParam.setBfield(bz); + o2::gpu::GPUO2InterfaceConfiguration config; + config.ReadConfigurableParam(config); + mRecoParam.init(bz, &config.configReconstruction); } void TrackBasedCalib::setInput(const o2::globaltracking::RecoContainer& input) diff --git a/Detectors/TRD/qc/CMakeLists.txt b/Detectors/TRD/qc/CMakeLists.txt index d631de1f54246..daba4928957f9 100644 --- a/Detectors/TRD/qc/CMakeLists.txt +++ b/Detectors/TRD/qc/CMakeLists.txt @@ -21,6 +21,7 @@ o2_add_library(TRDQC O2::DataFormatsTRD O2::DataFormatsGlobalTracking O2::DetectorsBase + O2::GPUTracking O2::MathUtils) o2_target_root_dictionary(TRDQC diff --git a/Detectors/TRD/qc/include/TRDQC/Tracking.h b/Detectors/TRD/qc/include/TRDQC/Tracking.h index 880b1727ab367..f39c64286d0cc 100644 --- a/Detectors/TRD/qc/include/TRDQC/Tracking.h +++ b/Detectors/TRD/qc/include/TRDQC/Tracking.h @@ -25,7 +25,7 @@ #include "ReconstructionDataFormats/GlobalTrackID.h" #include "DataFormatsTPC/TrackTPC.h" #include "DetectorsBase/Propagator.h" -#include "TRDBase/RecoParam.h" +#include "GPUTRDRecoParam.h" #include "Rtypes.h" #include "TH1.h" @@ -107,7 +107,7 @@ class Tracking float mMaxSnp{o2::base::Propagator::MAX_SIN_PHI}; ///< max snp when propagating tracks float mMaxStep{o2::base::Propagator::MAX_STEP}; ///< maximum step for propagation MatCorrType mMatCorr{MatCorrType::USEMatCorrNONE}; ///< if material correction should be done - RecoParam mRecoParam; ///< parameters required for TRD reconstruction + o2::gpu::GPUTRDRecoParam mRecoParam; ///< parameters required for TRD reconstruction bool mPID{true}; ///< if TPC only tracks are not available we don't fill PID info bool mApplyShift{true}; diff --git a/Detectors/TRD/qc/src/Tracking.cxx b/Detectors/TRD/qc/src/Tracking.cxx index 278ebe5391ff9..9a0df7efa323b 100644 --- a/Detectors/TRD/qc/src/Tracking.cxx +++ b/Detectors/TRD/qc/src/Tracking.cxx @@ -13,6 +13,7 @@ /// \brief Check the performance of the TRD in global tracking /// \author Ole Schmidt +#include "GPUO2InterfaceConfiguration.h" #include "TRDQC/Tracking.h" #include "DataFormatsGlobalTracking/RecoContainer.h" #include "DetectorsBase/GeometryManager.h" @@ -25,7 +26,9 @@ using namespace o2::trd::constants; void Tracking::init() { - mRecoParam.setBfield(o2::base::Propagator::Instance()->getNominalBz()); + o2::gpu::GPUO2InterfaceConfiguration config; + config.ReadConfigurableParam(config); + mRecoParam.init(o2::base::Propagator::Instance()->getNominalBz(), &config.configReconstruction); } void Tracking::setInput(const o2::globaltracking::RecoContainer& input) diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/TRDGlobalTrackingSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/TRDGlobalTrackingSpec.h index 9f3b9b27d37b5..93f07dd58445e 100644 --- a/Detectors/TRD/workflow/include/TRDWorkflow/TRDGlobalTrackingSpec.h +++ b/Detectors/TRD/workflow/include/TRDWorkflow/TRDGlobalTrackingSpec.h @@ -20,6 +20,7 @@ #include "TRDBase/GeometryFlat.h" #include "GPUO2ExternalUser.h" #include "GPUTRDTracker.h" +#include "GPUTRDRecoParam.h" #include "ReconstructionDataFormats/GlobalTrackID.h" #include "DataFormatsGlobalTracking/RecoContainer.h" #include "DataFormatsTRD/TrackTRD.h" @@ -34,7 +35,6 @@ #include "TPCCalibration/CorrectionMapsLoader.h" #include "GPUO2InterfaceRefit.h" #include "TPCFastTransform.h" -#include "TRDBase/RecoParam.h" #include "DataFormatsTPC/TrackTPC.h" #include "DataFormatsITS/TrackITS.h" #include "DataFormatsITSMFT/TrkClusRef.h" @@ -94,7 +94,7 @@ class TRDGlobalTracking : public o2::framework::Task // temporary members -> should go into processor (GPUTRDTracker or additional refit processor?) std::unique_ptr mTPCRefitter; ///< TPC refitter used for TPC tracks refit during the reconstruction const o2::tpc::ClusterNativeAccess* mTPCClusterIdxStruct = nullptr; ///< struct holding the TPC cluster indices - RecoParam mRecoParam; ///< parameters required for TRD reconstruction + o2::gpu::GPUTRDRecoParam mRecoParam; ///< parameters required for TRD reconstruction gsl::span mTrackletsRaw; ///< array of raw tracklets needed for TRD refit gsl::span mTrackletsCalib; ///< array of calibrated tracklets needed for TRD refit gsl::span mTPCTracksArray; ///< input TPC tracks used for refit diff --git a/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx b/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx index 9588888df5fc6..f2d4aad829fe5 100644 --- a/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx +++ b/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx @@ -43,6 +43,7 @@ // GPU header #include "GPUReconstruction.h" #include "GPUChainTracking.h" +#include "GPUChainTrackingGetters.inc" #include "GPUO2InterfaceConfiguration.h" #include "GPUO2InterfaceUtils.h" #include "GPUSettings.h" @@ -112,6 +113,8 @@ void TRDGlobalTracking::updateTimeDependentParams(ProcessingContext& pc) config.ReadConfigurableParam(config); config.configGRP.solenoidBzNominalGPU = GPUO2InterfaceUtils::getNominalGPUBz(*o2::base::GRPGeomHelper::instance().getGRPMagField()); config.configProcessing.o2PropagatorUseGPUField = false; + mRecoParam.init(o2::base::Propagator::Instance()->getNominalBz(), &config.configReconstruction); + mRec->SetSettings(&config.configGRP, &config.configReconstruction, &config.configProcessing, &cfgRecoStep); mChainTracking = mRec->AddChain(); @@ -127,12 +130,11 @@ void TRDGlobalTracking::updateTimeDependentParams(ProcessingContext& pc) mRec->RegisterGPUProcessor(mTracker, false); mChainTracking->SetTRDGeometry(std::move(mFlatGeo)); + mChainTracking->SetTRDRecoParam(&mRecoParam); if (mRec->Init()) { LOG(fatal) << "GPUReconstruction could not be initialized"; } - mRecoParam.setBfield(o2::base::Propagator::Instance()->getNominalBz()); - mTracker->PrintSettings(); LOG(info) << "Strict matching mode is " << ((mStrict) ? "ON" : "OFF"); LOGF(info, "The search road in time for ITS-TPC tracks is set to %.1f sigma and %.2f us are added to it on top", diff --git a/GPU/GPUTracking/Base/GPUConstantMem.h b/GPU/GPUTracking/Base/GPUConstantMem.h index efb83a7e874c8..94ccfa7fa6db9 100644 --- a/GPU/GPUTracking/Base/GPUConstantMem.h +++ b/GPU/GPUTracking/Base/GPUConstantMem.h @@ -57,7 +57,6 @@ struct GPUConstantMem { #ifdef GPUCA_HAS_ONNX GPUTPCNNClusterizer tpcNNClusterer[GPUCA_NSECTORS]; #endif - template GPUd() auto& getTRDTracker(); }; diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index 6a60eb9edd6d0..9e9344108ccfb 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -59,6 +59,7 @@ set(SRCS Merger/GPUTPCGMPhysicalTrackModel.cxx Merger/GPUTPCGMPolynomialFieldManager.cxx DataTypes/GPUTRDTrack.cxx + DataTypes/GPUTRDRecoParam.cxx TRDTracking/GPUTRDTracker.cxx TRDTracking/GPUTRDTrackletWord.cxx TRDTracking/GPUTRDTrackerKernels.cxx @@ -68,7 +69,7 @@ set(SRCS_DATATYPES DataTypes/GPUDataTypesConfig.cxx DataTypes/GPUConfigDump.cxx set(HDRS_CINT_O2 Merger/GPUTPCGMTrackParam.h Merger/GPUTPCGMMergedTrack.h Merger/GPUTPCGMSectorTrack.h Merger/GPUTPCGMBorderTrack.h TRDTracking/GPUTRDInterfaces.h) set(HDRS_CINT_DATATYPES DataTypes/GPUTPCGMMergedTrackHit.h) -set(HDRS_CINT_O2_ADDITIONAL DataTypes/GPUSettings.h Definitions/GPUSettingsList.h DataTypes/GPUDataTypesIO.h DataTypes/GPUDataTypesConfig.h DataTypes/GPUDataTypesQA.h DataTypes/GPUTRDTrack.h DataTypes/CalibdEdxTrackTopologyPol.h DataTypes/CalibdEdxTrackTopologySpline.h) # Manual dependencies for ROOT dictionary generation +set(HDRS_CINT_O2_ADDITIONAL DataTypes/GPUSettings.h Definitions/GPUSettingsList.h DataTypes/GPUDataTypesIO.h DataTypes/GPUDataTypesConfig.h DataTypes/GPUDataTypesQA.h DataTypes/GPUTRDTrack.h DataTypes/GPUTRDRecoParam.h DataTypes/CalibdEdxTrackTopologyPol.h DataTypes/CalibdEdxTrackTopologySpline.h) # Manual dependencies for ROOT dictionary generation set(SRCS_NO_CINT DataTypes/GPUMemorySizeScalers.cxx diff --git a/GPU/GPUTracking/DataTypes/GPUDataTypesIO.h b/GPU/GPUTracking/DataTypes/GPUDataTypesIO.h index fd98cba1dadaa..76fa569a16824 100644 --- a/GPU/GPUTracking/DataTypes/GPUDataTypesIO.h +++ b/GPU/GPUTracking/DataTypes/GPUDataTypesIO.h @@ -95,6 +95,7 @@ class TPCFastTransform; struct TPCPadGainCalib; struct TPCZSLinkMapping; +class GPUTRDRecoParam; class GPUTPCTrack; class GPUTPCHitId; class GPUTPCGMMergedTrack; @@ -135,7 +136,7 @@ struct GPUCalibObjectsTemplate { // use only pointers on PODs or flat objects he typename S::type* dEdxCalibContainer = nullptr; typename S>::type* o2Propagator = nullptr; typename S::type* itsPatternDict = nullptr; - + typename S::type* trdRecoParam = nullptr; // NN clusterizer objects typename S::type* nnClusterizerNetworks[3] = {nullptr, nullptr, nullptr}; }; diff --git a/GPU/GPUTracking/DataTypes/GPUTRDRecoParam.cxx b/GPU/GPUTracking/DataTypes/GPUTRDRecoParam.cxx new file mode 100644 index 0000000000000..70b445f7befc0 --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUTRDRecoParam.cxx @@ -0,0 +1,100 @@ +// 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 GPUTRDRecoParam.cxx +/// \brief Error parameterizations and helper functions for TRD reconstruction +/// \author Ole Schmidt + +#include "GPUSettings.h" +#include "GPUTRDRecoParam.h" +#include "GPUCommonLogger.h" +#include "GPUCommonMath.h" + +using namespace o2::gpu; + +// error parameterizations taken from http://cds.cern.ch/record/2724259 Appendix A +void GPUTRDRecoParam::init(float bz, const GPUSettingsRec* rec) +{ + float resRPhiIdeal2 = rec ? rec->trd.trkltResRPhiIdeal * rec->trd.trkltResRPhiIdeal : 1.6e-3f; + + if (CAMath::Abs(CAMath::Abs(bz) - 2) < 0.1) { + if (bz > 0) { + // magnetic field +0.2 T + mRPhiA2 = resRPhiIdeal2; + mRPhiB = -1.43e-2f; + mRPhiC2 = 4.55e-2f; + + mDyA2 = 1.225e-3f; + mDyB = -9.8e-3f; + mDyC2 = 3.88e-2f; + + mAngleToDyA = -0.1f; + mAngleToDyB = 1.89f; + mAngleToDyC = -0.4f; + } else { + // magnetic field -0.2 T + mRPhiA2 = resRPhiIdeal2; + mRPhiB = 1.43e-2f; + mRPhiC2 = 4.55e-2f; + + mDyA2 = 1.225e-3f; + mDyB = 9.8e-3f; + mDyC2 = 3.88e-2f; + + mAngleToDyA = 0.1f; + mAngleToDyB = 1.89f; + mAngleToDyC = 0.4f; + } + } else if (CAMath::Abs(CAMath::Abs(bz) - 5) < 0.1) { + if (bz > 0) { + // magnetic field +0.5 T + mRPhiA2 = resRPhiIdeal2; + mRPhiB = 0.125f; + mRPhiC2 = 0.0961f; + + mDyA2 = 1.681e-3f; + mDyB = 0.15f; + mDyC2 = 0.1849f; + + mAngleToDyA = 0.13f; + mAngleToDyB = 2.43f; + mAngleToDyC = -0.58f; + } else { + // magnetic field -0.5 T + mRPhiA2 = resRPhiIdeal2; + mRPhiB = -0.14f; + mRPhiC2 = 0.1156f; + + mDyA2 = 2.209e-3f; + mDyB = -0.15f; + mDyC2 = 0.2025f; + + mAngleToDyA = -0.15f; + mAngleToDyB = 2.34f; + mAngleToDyC = 0.56f; + } + } else { + LOGP(warning, "No error parameterization available for Bz= {}. Keeping default value (sigma_y = const. = 1cm)", bz); + } + LOGP(info, "Loaded parameterizations for Bz={}: PhiRes:[{},{},{}] DyRes:[{},{},{}] Angle2Dy:[{},{},{}]", + bz, mRPhiA2, mRPhiB, mRPhiC2, mDyA2, mDyB, mDyC2, mAngleToDyA, mAngleToDyB, mAngleToDyC); +} + +void GPUTRDRecoParam::recalcTrkltCov(const float tilt, const float snp, const float rowSize, float* cov) const +{ + float t2 = tilt * tilt; // tan^2 (tilt) + float c2 = 1.f / (1.f + t2); // cos^2 (tilt) + float sy2 = getRPhiRes(snp); + float sz2 = rowSize * rowSize / 12.f; + cov[0] = c2 * (sy2 + t2 * sz2); + cov[1] = c2 * tilt * (sz2 - sy2); + cov[2] = c2 * (t2 * sy2 + sz2); +} diff --git a/GPU/GPUTracking/DataTypes/GPUTRDRecoParam.h b/GPU/GPUTracking/DataTypes/GPUTRDRecoParam.h new file mode 100644 index 0000000000000..ad0285487d3c3 --- /dev/null +++ b/GPU/GPUTracking/DataTypes/GPUTRDRecoParam.h @@ -0,0 +1,84 @@ +// 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 RecoParam.h +/// \brief Error parameterizations and helper functions for TRD reconstruction +/// \author Ole Schmidt + +#ifndef O2_GPU_TRD_RECOPARAM_H +#define O2_GPU_TRD_RECOPARAM_H + +#include "GPUCommonDef.h" +#include "GPUCommonRtypes.h" +#include "GPUCommonArray.h" + +namespace o2 +{ +namespace gpu +{ +struct GPUSettingsRec; + +class GPUTRDRecoParam +{ + public: + GPUTRDRecoParam() = default; + GPUTRDRecoParam(const GPUTRDRecoParam&) = default; + ~GPUTRDRecoParam() = default; + + /// Load parameterization for given magnetic field + void init(float bz, const GPUSettingsRec* rec = nullptr); + +#if !defined(GPUCA_GPUCODE_DEVICE) + /// Recalculate tracklet covariance based on phi angle of related track + GPUd() void recalcTrkltCov(const float tilt, const float snp, const float rowSize, std::array& cov) const + { + recalcTrkltCov(tilt, snp, rowSize, cov.data()); + } +#endif + GPUd() void recalcTrkltCov(const float tilt, const float snp, const float rowSize, float* cov) const; + + /// Get tracklet r-phi resolution for given phi angle + /// Resolution depends on the track angle sin(phi) = snp and is approximated by the formula + /// sigma_y(snp) = sqrt(a^2 + c^2 * (snp - b)^2) + /// more details are given in http://cds.cern.ch/record/2724259 in section 5.3.3 + /// \param phi angle of related track + /// \return sigma_y^2 of tracklet + GPUd() float getRPhiRes(float snp) const { return (mRPhiA2 + mRPhiC2 * (snp - mRPhiB) * (snp - mRPhiB)); } + GPUd() float getDyRes(float snp) const { return mDyA2 + mDyC2 * (snp - mDyB) * (snp - mDyB); } // // a^2 + c^2 * (snp - b)^2 + GPUd() float convertAngleToDy(float snp) const { return mAngleToDyA + mAngleToDyB * snp + mAngleToDyC * snp * snp; } // a + b*snp + c*snp^2 is more accurate than sin(phi) = (dy / xDrift) / sqrt(1+(dy/xDrift)^2) + + /// Get tracklet z correction coefficient for track-eta based corraction + GPUd() float getZCorrCoeffNRC() const { return mZCorrCoefNRC; } + + private: + // tracklet error parameterization depends on the magnetic field + // rphi + float mRPhiA2{1.f}; ///< parameterization for tracklet position resolution + float mRPhiB{0.f}; ///< parameterization for tracklet position resolution + float mRPhiC2{0.f}; ///< parameterization for tracklet position resolution + // angle + float mDyA2{1.225e-3f}; ///< parameterization for tracklet angular resolution + float mDyB{0.f}; ///< parameterization for tracklet angular resolution + float mDyC2{0.f}; ///< parameterization for tracklet angular resolution + // angle to Dy + float mAngleToDyA; // parameterization for conversion track angle -> tracklet deflection + float mAngleToDyB; // parameterization for conversion track angle -> tracklet deflection + float mAngleToDyC; // parameterization for conversion track angle -> tracklet deflection + + float mZCorrCoefNRC{1.4f}; ///< tracklet z-position depends linearly on track dip angle + + ClassDefNV(GPUTRDRecoParam, 2); +}; + +} // namespace gpu +} // namespace o2 + +#endif // O2_GPU_TRD_RECOPARAM_H diff --git a/GPU/GPUTracking/GPUTrackingLinkDef_O2.h b/GPU/GPUTracking/GPUTrackingLinkDef_O2.h index 8e99514a817c5..46ced1e0481f9 100644 --- a/GPU/GPUTracking/GPUTrackingLinkDef_O2.h +++ b/GPU/GPUTracking/GPUTrackingLinkDef_O2.h @@ -27,6 +27,7 @@ #pragma link C++ struct o2::gpu::GPUTPCGMSectorTrack::sectorTrackParam + ; #pragma link C++ class o2::gpu::trackInterface < o2::gpu::GPUTPCGMTrackParam> + ; #pragma link C++ class o2::gpu::GPUTRDTrack_t < o2::gpu::trackInterface < o2::gpu::GPUTPCGMTrackParam>> + ; +#pragma link C++ class o2::gpu::GPUTRDRecoParam + ; #pragma link C++ class o2::gpu::gputpcgmmergertypes::GPUTPCOuterParam + ; #pragma link C++ class o2::gpu::gputpcgmmergertypes::InterpolationErrorHit + ; diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index 5c951053e155b..7216de0535329 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -34,6 +34,7 @@ #include "GPUTRDTracker.h" #include "AliHLTTPCRawCluster.h" #include "GPUTRDTrackletLabels.h" +#include "GPUTRDRecoParam.h" #include "display/GPUDisplayInterface.h" #include "GPUQA.h" #include "GPULogging.h" @@ -435,6 +436,9 @@ void GPUChainTracking::UpdateGPUCalibObjects(int32_t stream, const GPUCalibObjec memcpy((void*)mFlatObjectsShadow.mCalibObjects.trdGeometry, (const void*)processors()->calibObjects.trdGeometry, sizeof(*processors()->calibObjects.trdGeometry)); mFlatObjectsShadow.mCalibObjects.trdGeometry->clearInternalBufferPtr(); } + if (processors()->calibObjects.trdRecoParam && (ptrMask == nullptr || ptrMask->trdRecoParam)) { + memcpy((void*)mFlatObjectsShadow.mCalibObjects.trdRecoParam, (const void*)processors()->calibObjects.trdRecoParam, sizeof(*processors()->calibObjects.trdRecoParam)); + } if (processors()->calibObjects.tpcPadGain && (ptrMask == nullptr || ptrMask->tpcPadGain)) { memcpy((void*)mFlatObjectsShadow.mCalibObjects.tpcPadGain, (const void*)processors()->calibObjects.tpcPadGain, sizeof(*processors()->calibObjects.tpcPadGain)); } @@ -536,6 +540,9 @@ void* GPUChainTracking::GPUTrackingFlatObjects::SetPointersFlatObjects(void* mem if (mChainTracking->processors()->calibObjects.trdGeometry) { computePointerWithAlignment(mem, mCalibObjects.trdGeometry, 1); } + if (mChainTracking->processors()->calibObjects.trdRecoParam) { + computePointerWithAlignment(mem, mCalibObjects.trdRecoParam, 1); + } computePointerWithAlignment(mem, mCalibObjects.o2Propagator, 1); if (!mChainTracking->processors()->calibObjects.o2Propagator) { mCalibObjects.o2Propagator = nullptr; // Always reserve memory for o2::Propagator, since it may be propagatred only during run() not during init(). @@ -602,6 +609,12 @@ void GPUChainTracking::SetTRDGeometry(std::unique_ptr&& g processors()->calibObjects.trdGeometry = mTRDGeometryU.get(); } +void GPUChainTracking::SetTRDRecoParam(std::unique_ptr&& par) +{ + mTRDRecoParamU = std::move(par); + processors()->calibObjects.trdRecoParam = mTRDRecoParamU.get(); +} + int32_t GPUChainTracking::DoQueuedUpdates(int32_t stream, bool updateSlave) { int32_t retVal = 0; diff --git a/GPU/GPUTracking/Global/GPUChainTracking.h b/GPU/GPUTracking/Global/GPUChainTracking.h index 2dd1ece856ecf..fd75136f51d76 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.h +++ b/GPU/GPUTracking/Global/GPUChainTracking.h @@ -59,6 +59,7 @@ class GPUDisplayInterface; class GPUQA; class GPUTPCClusterStatistics; class GPUTRDGeometry; +class GPUTRDRecoParam; class TPCFastTransform; class GPUTrackingInputProvider; struct GPUChainTrackingFinalContext; @@ -178,13 +179,16 @@ class GPUChainTracking : public GPUChain const o2::tpc::CalibdEdxContainer* GetdEdxCalibContainer() const; const o2::base::MatLayerCylSet* GetMatLUT() const; const GPUTRDGeometry* GetTRDGeometry() const; + const GPUTRDRecoParam* GetTRDRecoParam() const; const o2::base::Propagator* GetO2Propagator() const; const o2::base::Propagator* GetDeviceO2Propagator(); void SetTPCFastTransform(std::unique_ptr&& tpcFastTransform, std::unique_ptr&& tpcTransformHelper); void SetMatLUT(std::unique_ptr&& lut); void SetTRDGeometry(std::unique_ptr&& geo); + void SetTRDRecoParam(std::unique_ptr&& par); void SetMatLUT(const o2::base::MatLayerCylSet* lut); void SetTRDGeometry(const o2::trd::GeometryFlat* geo); + void SetTRDRecoParam(const GPUTRDRecoParam* par); void SetO2Propagator(const o2::base::Propagator* prop); void SetCalibObjects(const GPUCalibObjectsConst& obj); void SetCalibObjects(const GPUCalibObjects& obj); @@ -267,6 +271,7 @@ class GPUChainTracking : public GPUChain std::unique_ptr mdEdxCalibContainerU; // TPC dEdx calibration container std::unique_ptr mMatLUTU; // Material Lookup Table std::unique_ptr mTRDGeometryU; // TRD Geometry + std::unique_ptr mTRDRecoParamU; // TRD RecoParam // Ptrs to internal buffers std::unique_ptr mClusterNativeAccess, mClusterNativeAccessReduced; diff --git a/GPU/GPUTracking/Global/GPUChainTrackingGetters.inc b/GPU/GPUTracking/Global/GPUChainTrackingGetters.inc index 5b72a8f23c242..b3b1773ec664e 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingGetters.inc +++ b/GPU/GPUTracking/Global/GPUChainTrackingGetters.inc @@ -26,9 +26,11 @@ inline const TPCZSLinkMapping* GPUChainTracking::GetTPCZSLinkMapping() const { r inline const o2::tpc::CalibdEdxContainer* GPUChainTracking::GetdEdxCalibContainer() const { return processors()->calibObjects.dEdxCalibContainer; } inline const o2::base::MatLayerCylSet* GPUChainTracking::GetMatLUT() const { return processors()->calibObjects.matLUT; } inline const GPUTRDGeometry* GPUChainTracking::GetTRDGeometry() const { return (GPUTRDGeometry*)processors()->calibObjects.trdGeometry; } +inline const GPUTRDRecoParam* GPUChainTracking::GetTRDRecoParam() const { return processors()->calibObjects.trdRecoParam; } inline const o2::base::Propagator* GPUChainTracking::GetO2Propagator() const { return processors()->calibObjects.o2Propagator; } inline void GPUChainTracking::SetMatLUT(const o2::base::MatLayerCylSet* lut) { processors()->calibObjects.matLUT = lut; } inline void GPUChainTracking::SetTRDGeometry(const o2::trd::GeometryFlat* geo) { processors()->calibObjects.trdGeometry = geo; } +inline void GPUChainTracking::SetTRDRecoParam(const GPUTRDRecoParam* par) { processors()->calibObjects.trdRecoParam = par; } inline void GPUChainTracking::SetCalibObjects(const GPUCalibObjectsConst& obj) { processors()->calibObjects = obj; } inline void GPUChainTracking::SetCalibObjects(const GPUCalibObjects& obj) { memcpy((void*)&processors()->calibObjects, (const void*)&obj, sizeof(obj)); } } // namespace o2::gpu diff --git a/GPU/GPUTracking/Global/GPUChainTrackingIO.cxx b/GPU/GPUTracking/Global/GPUChainTrackingIO.cxx index dd11e9989f684..6f24415564a8c 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingIO.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingIO.cxx @@ -20,6 +20,7 @@ #include "GPUTPCTrack.h" #include "GPUTPCHitId.h" #include "GPUTRDTrackletWord.h" +#include "GPUTRDRecoParam.h" #include "AliHLTTPCClusterMCData.h" #include "GPUTPCMCInfo.h" #include "GPUTRDTrack.h" @@ -337,6 +338,11 @@ void GPUChainTracking::DumpSettings(const char* dir) f += "trdgeometry.dump"; DumpStructToFile(processors()->calibObjects.trdGeometry, f.c_str()); } + if (processors()->calibObjects.trdRecoParam != nullptr) { + f = dir; + f += "trdrecoparam.dump"; + DumpStructToFile(processors()->calibObjects.trdRecoParam, f.c_str()); + } } void GPUChainTracking::ReadSettings(const char* dir) @@ -382,4 +388,8 @@ void GPUChainTracking::ReadSettings(const char* dir) f += "trdgeometry.dump"; mTRDGeometryU = ReadStructFromFile(f.c_str()); processors()->calibObjects.trdGeometry = mTRDGeometryU.get(); + f = dir; + f += "trdrecoparam.dump"; + mTRDRecoParamU = ReadStructFromFile(f.c_str()); + processors()->calibObjects.trdRecoParam = mTRDRecoParamU.get(); } diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx b/GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx index 2f754d2416bc1..d5d400e30df53 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx @@ -23,6 +23,7 @@ #include "GPUCommonMath.h" #include "GPUCommonAlgorithm.h" #include "GPUConstantMem.h" +#include "GPUTRDRecoParam.h" using namespace o2::gpu; @@ -92,7 +93,7 @@ void* GPUTRDTracker_t::SetPointersTracks(void* base) } template -GPUTRDTracker_t::GPUTRDTracker_t() : mR(nullptr), mIsInitialized(false), mGenerateSpacePoints(false), mProcessPerTimeFrame(false), mNAngleHistogramBins(25), mAngleHistogramRange(50), mMemoryPermanent(-1), mMemoryTracklets(-1), mMemoryTracks(-1), mNMaxCollisions(0), mNMaxTracks(0), mNMaxSpacePoints(0), mTracks(nullptr), mTrackAttribs(nullptr), mNCandidates(1), mNTracks(0), mNEvents(0), mMaxBackendThreads(100), mTrackletIndexArray(nullptr), mHypothesis(nullptr), mCandidates(nullptr), mSpacePoints(nullptr), mGeo(nullptr), mRPhiA2(0), mRPhiB(0), mRPhiC2(0), mDyA2(0), mDyB(0), mDyC2(0), mAngleToDyA(0), mAngleToDyB(0), mAngleToDyC(0), mDebugOutput(false), mMaxEta(0.84f), mRoadZ(18.f), mZCorrCoefNRC(1.4f), mTPCVdrift(2.58f), mTPCTDriftOffset(0.f), mDebug(new GPUTRDTrackerDebug()) +GPUTRDTracker_t::GPUTRDTracker_t() : mR(nullptr), mIsInitialized(false), mGenerateSpacePoints(false), mProcessPerTimeFrame(false), mNAngleHistogramBins(25), mAngleHistogramRange(50), mMemoryPermanent(-1), mMemoryTracklets(-1), mMemoryTracks(-1), mNMaxCollisions(0), mNMaxTracks(0), mNMaxSpacePoints(0), mTracks(nullptr), mTrackAttribs(nullptr), mNCandidates(1), mNTracks(0), mNEvents(0), mMaxBackendThreads(100), mTrackletIndexArray(nullptr), mHypothesis(nullptr), mCandidates(nullptr), mSpacePoints(nullptr), mGeo(nullptr), mRecoParam(nullptr), mDebugOutput(false), mMaxEta(0.84f), mRoadZ(18.f), mZCorrCoefNRC(1.4f), mTPCVdrift(2.58f), mTPCTDriftOffset(0.f), mDebug(new GPUTRDTrackerDebug()) { //-------------------------------------------------------------------- // Default constructor @@ -114,9 +115,8 @@ void GPUTRDTracker_t::InitializeProcessor() //-------------------------------------------------------------------- // Initialise tracker //-------------------------------------------------------------------- - + mRecoParam = GetConstantMem()->calibObjects.trdRecoParam; UpdateGeometry(); - mDebug->ExpandVectors(); mIsInitialized = true; } @@ -131,42 +131,6 @@ void GPUTRDTracker_t::UpdateGeometry() if (!mGeo) { GPUFatal("TRD geometry must be provided externally"); } - float Bz = Param().bzkG; - float resRPhiIdeal2 = Param().rec.trd.trkltResRPhiIdeal * Param().rec.trd.trkltResRPhiIdeal; - GPUInfo("Initializing with B-field: %f kG", Bz); - if (CAMath::Abs(CAMath::Abs(Bz) - 2) < 0.1f) { - // magnetic field +-0.2 T - if (Bz > 0) { - GPUInfo("Loading error parameterization for Bz = +2 kG"); - mRPhiA2 = resRPhiIdeal2, mRPhiB = -1.43e-2f, mRPhiC2 = 4.55e-2f; - mDyA2 = 1.225e-3f, mDyB = -9.8e-3f, mDyC2 = 3.88e-2f; - mAngleToDyA = -0.1f, mAngleToDyB = 1.89f, mAngleToDyC = -0.4f; - } else { - GPUInfo("Loading error parameterization for Bz = -2 kG"); - mRPhiA2 = resRPhiIdeal2, mRPhiB = 1.43e-2f, mRPhiC2 = 4.55e-2f; - mDyA2 = 1.225e-3f, mDyB = 9.8e-3f, mDyC2 = 3.88e-2f; - mAngleToDyA = 0.1f, mAngleToDyB = 1.89f, mAngleToDyC = 0.4f; - } - } else if (CAMath::Abs(CAMath::Abs(Bz) - 5) < 0.1f) { - // magnetic field +-0.5 T - if (Bz > 0) { - GPUInfo("Loading error parameterization for Bz = +5 kG"); - mRPhiA2 = resRPhiIdeal2, mRPhiB = 0.125f, mRPhiC2 = 0.0961f; - mDyA2 = 1.681e-3f, mDyB = 0.15f, mDyC2 = 0.1849f; - mAngleToDyA = 0.13f, mAngleToDyB = 2.43f, mAngleToDyC = -0.58f; - } else { - GPUInfo("Loading error parameterization for Bz = -5 kG"); - mRPhiA2 = resRPhiIdeal2, mRPhiB = -0.14f, mRPhiC2 = 0.1156f; - mDyA2 = 2.209e-3f, mDyB = -0.15f, mDyC2 = 0.2025f; - mAngleToDyA = -0.15f, mAngleToDyB = 2.34f, mAngleToDyC = 0.56f; - } - } else { - // magnetic field 0 T or another value which is not covered by the error parameterizations - // using default values instead - GPUWarning("No error parameterization available for Bz = %.2f kG. Keeping default value (sigma_y = const. = 1cm)", Bz); - mRPhiA2 = 1.f; - } - // obtain average radius of TRD chambers float x0[kNLayers] = {300.2f, 312.8f, 325.4f, 338.0f, 350.6f, 363.2f}; // used as default value in case no transformation matrix can be obtained auto* matrix = mGeo->GetClusterMatrix(0); @@ -967,7 +931,7 @@ GPUd() void GPUTRDTracker_t::RecalcTrkltCov(const float tilt, cons //-------------------------------------------------------------------- float t2 = tilt * tilt; // tan^2 (tilt) float c2 = 1.f / (1.f + t2); // cos^2 (tilt) - float sy2 = GetRPhiRes(snp); + float sy2 = mRecoParam->getRPhiRes(snp); float sz2 = rowSize * rowSize / 12.f; cov[0] = c2 * (sy2 + t2 * sz2); cov[1] = c2 * tilt * (sz2 - sy2); @@ -977,8 +941,8 @@ GPUd() void GPUTRDTracker_t::RecalcTrkltCov(const float tilt, cons template GPUd() float GPUTRDTracker_t::GetAngularPull(float dYtracklet, float snp) const { - float dYtrack = ConvertAngleToDy(snp); - float dYresolution = GetAngularResolution(snp); + float dYtrack = mRecoParam->convertAngleToDy(snp); + float dYresolution = mRecoParam->getDyRes(snp); if (dYresolution < 1e-6f) { return 999.f; } diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTracker.h b/GPU/GPUTracking/TRDTracking/GPUTRDTracker.h index f8fa0342ee62d..5d7530ccecc11 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTracker.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTracker.h @@ -38,6 +38,7 @@ class GPUTRDGeometry; class GPUChainTracking; template class GPUTRDTrackerDebug; +class GPUTRDRecoParam; //------------------------------------------------------------------------- template @@ -114,9 +115,6 @@ class GPUTRDTracker_t : public GPUProcessor GPUd() bool AdjustSector(PROP* prop, TRDTRK* t) const; GPUd() int32_t GetSector(float alpha) const; GPUd() float GetAlphaOfSector(const int32_t sec) const; - GPUd() float GetRPhiRes(float snp) const { return (mRPhiA2 + mRPhiC2 * (snp - mRPhiB) * (snp - mRPhiB)); } // parametrization obtained from track-tracklet residuals: - GPUd() float GetAngularResolution(float snp) const { return mDyA2 + mDyC2 * (snp - mDyB) * (snp - mDyB); } // a^2 + c^2 * (snp - b)^2 - GPUd() float ConvertAngleToDy(float snp) const { return mAngleToDyA + mAngleToDyB * snp + mAngleToDyC * snp * snp; } // a + b*snp + c*snp^2 is more accurate than sin(phi) = (dy / xDrift) / sqrt(1+(dy/xDrift)^2) GPUd() float GetAngularPull(float dYtracklet, float snp) const; GPUd() void RecalcTrkltCov(const float tilt, const float snp, const float rowSize, float (&cov)[3]); GPUd() void FindChambersInRoad(const TRDTRK* t, const float roadY, const float roadZ, const int32_t iLayer, int32_t* det, const float zMax, const float alpha, const float zShiftTrk) const; @@ -174,16 +172,7 @@ class GPUTRDTracker_t : public GPUProcessor TRDTRK* mCandidates; // array of tracks for multiple hypothesis tracking GPUTRDSpacePoint* mSpacePoints; // array with tracklet coordinates in global tracking frame const GPUTRDGeometry* mGeo; // TRD geometry - /// ---- error parametrization depending on magnetic field ---- - float mRPhiA2; // parameterization for tracklet position resolution - float mRPhiB; // parameterization for tracklet position resolution - float mRPhiC2; // parameterization for tracklet position resolution - float mDyA2; // parameterization for tracklet angular resolution - float mDyB; // parameterization for tracklet angular resolution - float mDyC2; // parameterization for tracklet angular resolution - float mAngleToDyA; // parameterization for conversion track angle -> tracklet deflection - float mAngleToDyB; // parameterization for conversion track angle -> tracklet deflection - float mAngleToDyC; // parameterization for conversion track angle -> tracklet deflection + const GPUTRDRecoParam* mRecoParam; // TRD RecoParam /// ---- end error parametrization ---- bool mDebugOutput; // store debug output static constexpr const float sRadialOffset = -0.1f; // due to (possible) mis-calibration of t0 -> will become obsolete when tracklet conversion is done outside of the tracker diff --git a/GPU/GPUTracking/TRDTracking/macros/run_trd_tracker.C b/GPU/GPUTracking/TRDTracking/macros/run_trd_tracker.C index acfcf92370b00..e4b37500e1a60 100644 --- a/GPU/GPUTracking/TRDTracking/macros/run_trd_tracker.C +++ b/GPU/GPUTracking/TRDTracking/macros/run_trd_tracker.C @@ -24,6 +24,7 @@ #include "GPUTRDTrackletWord.h" #include "GPUTRDInterfaces.h" #include "GPUTRDGeometry.h" +#include "GPUTRDRecoParam.h" // O2 header #include "CommonUtils/NameConf.h" @@ -58,7 +59,7 @@ void run_trd_tracker(std::string path = "./", geo->createPadPlaneArray(); geo->createClusterMatrixArray(); const o2::trd::GeometryFlat geoFlat(*geo); - + o2::gpu::GPUTRDRecoParam trdRecoParam; //-------- init GPU reconstruction --------// // different settings are defined in GPUSettingsList.h GPUSettingsGRP cfgGRP; // defaults should be ok @@ -85,6 +86,7 @@ void run_trd_tracker(std::string path = "./", rec->RegisterGPUProcessor(tracker, false); chainTracking->SetTRDGeometry(&geoFlat); + chainTracking->SetTRDRecoParam(&trdRecoParam); if (rec->Init()) { printf("ERROR: GPUReconstruction not initialized\n"); } diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h index d610269abca81..8dfbdaff7272f 100644 --- a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -85,6 +85,7 @@ struct TPCPadGainCalib; struct TPCZSLinkMapping; struct GPUSettingsO2; struct GPUSettingsProcessingNNclusterizer; +class GPUTRDRecoParam; class GPUO2InterfaceQA; struct GPUTrackingInOutPointers; struct GPUTrackingInOutZS; @@ -212,6 +213,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task std::unique_ptr mTPCZSLinkMapping; std::unique_ptr mTPCVDriftHelper; std::unique_ptr mTRDGeometry; + std::unique_ptr mTRDRecoParam; std::unique_ptr mConfig; std::unique_ptr mConfParam; std::unique_ptr mTimer; @@ -245,6 +247,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task bool mMatLUTCreated = false; bool mITSGeometryCreated = false; bool mTRDGeometryCreated = false; + bool mTRDRecoParamCreated = false; bool mPropagatorInstanceCreated = false; int32_t mTPCCutAtTimeBin = -1; }; diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 7b1db436dbf7e..a8f95841a4dc9 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -73,6 +73,7 @@ #include "DataFormatsTRD/RecoInputContainer.h" #include "TRDBase/Geometry.h" #include "TRDBase/GeometryFlat.h" +#include "GPUTRDRecoParam.h" #include "ITSBase/GeometryTGeo.h" #include "CommonUtils/DebugStreamer.h" #include "GPUReconstructionConvert.h" @@ -273,6 +274,9 @@ void GPURecoWorkflowSpec::init(InitContext& ic) if (mSpecConfig.readTRDtracklets) { mTRDGeometry = std::make_unique(); mConfig->configCalib.trdGeometry = mTRDGeometry.get(); + + mTRDRecoParam = std::make_unique(); + mConfig->configCalib.trdRecoParam = mTRDRecoParam.get(); } mConfig->configProcessing.willProvideO2PropagatorLate = true; @@ -1059,14 +1063,21 @@ void GPURecoWorkflowSpec::doCalibUpdates(o2::framework::ProcessingContext& pc, c } mMatLUTCreated = true; } - if (mSpecConfig.readTRDtracklets && !mTRDGeometryCreated) { - auto gm = o2::trd::Geometry::instance(); - gm->createPadPlaneArray(); - gm->createClusterMatrixArray(); - mTRDGeometry = std::make_unique(*gm); - newCalibObjects.trdGeometry = mConfig->configCalib.trdGeometry = mTRDGeometry.get(); - LOG(info) << "Loaded TRD geometry"; - mTRDGeometryCreated = true; + if (mSpecConfig.readTRDtracklets) { + if (!mTRDGeometryCreated) { + auto gm = o2::trd::Geometry::instance(); + gm->createPadPlaneArray(); + gm->createClusterMatrixArray(); + mTRDGeometry = std::make_unique(*gm); + newCalibObjects.trdGeometry = mConfig->configCalib.trdGeometry = mTRDGeometry.get(); + LOG(info) << "Loaded TRD geometry"; + mTRDGeometryCreated = true; + } + if (!mTRDRecoParamCreated) { + mTRDRecoParam = std::make_unique(); + newCalibObjects.trdRecoParam = mConfig->configCalib.trdRecoParam = mTRDRecoParam.get(); + mTRDRecoParamCreated = true; + } } } needCalibUpdate = fetchCalibsCCDBTPC(pc, newCalibObjects, oldCalibObjects) || needCalibUpdate; From 8e1f22798d5e2ccfd03ace4ea07c45a18845e3e2 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 3 Feb 2026 10:48:58 +0100 Subject: [PATCH 141/234] Disable tests for reverted exceptions (#15011) --- Framework/Core/test/test_TypeToTaskName.cxx | 60 ++++++++++----------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/Framework/Core/test/test_TypeToTaskName.cxx b/Framework/Core/test/test_TypeToTaskName.cxx index b7b440b13ecfd..af51bc04613f5 100644 --- a/Framework/Core/test/test_TypeToTaskName.cxx +++ b/Framework/Core/test/test_TypeToTaskName.cxx @@ -18,48 +18,48 @@ using namespace o2::framework; TEST_CASE("TypeIdHelpers_BasicConversion") { // Basic CamelCase to snake-case conversion - REQUIRE((type_to_task_name(std::string_view("SimpleTask")) == "simple-task")); - REQUIRE((type_to_task_name(std::string_view("MyTask")) == "my-task")); - REQUIRE((type_to_task_name(std::string_view("Task")) == "task")); +// REQUIRE((type_to_task_name(std::string_view("SimpleTask")) == "simple-task")); +// REQUIRE((type_to_task_name(std::string_view("MyTask")) == "my-task")); +// REQUIRE((type_to_task_name(std::string_view("Task")) == "task")); } TEST_CASE("TypeIdHelpers_AbbreviationConsolidation") { // Test ALICE detector abbreviations - REQUIRE(type_to_task_name(std::string_view("ITSQA")) == "its-qa"); - REQUIRE(type_to_task_name(std::string_view("TPCQCTask")) == "tpc-qc-task"); +// REQUIRE(type_to_task_name(std::string_view("ITSQA")) == "its-qa"); +// REQUIRE(type_to_task_name(std::string_view("TPCQCTask")) == "tpc-qc-task"); REQUIRE(type_to_task_name(std::string_view("EMCALQATask")) == "emcal-qa-task"); - REQUIRE(type_to_task_name(std::string_view("HMPIDTask")) == "hmpid-task"); - REQUIRE(type_to_task_name(std::string_view("ITSTPCTask")) == "its-tpc-task"); - REQUIRE(type_to_task_name(std::string_view("QCFV0Task")) == "qc-fv0-task"); +// REQUIRE(type_to_task_name(std::string_view("HMPIDTask")) == "hmpid-task"); +// REQUIRE(type_to_task_name(std::string_view("ITSTPCTask")) == "its-tpc-task"); +// REQUIRE(type_to_task_name(std::string_view("QCFV0Task")) == "qc-fv0-task"); } -TEST_CASE("TypeIdHelpers_QualityControlAbbreviations") -{ - // Test quality control abbreviations - REQUIRE(type_to_task_name(std::string_view("QATask")) == "qa-task"); - REQUIRE(type_to_task_name(std::string_view("QCTask")) == "qc-task"); - REQUIRE(type_to_task_name(std::string_view("QCDAnalysis")) == "qcd-analysis"); -} +//TEST_CASE("TypeIdHelpers_QualityControlAbbreviations") +//{ +// // Test quality control abbreviations +// REQUIRE(type_to_task_name(std::string_view("QATask")) == "qa-task"); +// REQUIRE(type_to_task_name(std::string_view("QCTask")) == "qc-task"); +// REQUIRE(type_to_task_name(std::string_view("QCDAnalysis")) == "qcd-analysis"); +//} TEST_CASE("TypeIdHelpers_ComplexNames") { // Test complex combinations - REQUIRE(type_to_task_name(std::string_view("ITSQAAnalysisTask")) == "its-qa-analysis-task"); +// REQUIRE(type_to_task_name(std::string_view("ITSQAAnalysisTask")) == "its-qa-analysis-task"); REQUIRE(type_to_task_name(std::string_view("TPCEMCQCTask")) == "tpc-emc-qc-task"); - REQUIRE(type_to_task_name(std::string_view("MyITSTask")) == "my-its-task"); +// REQUIRE(type_to_task_name(std::string_view("MyITSTask")) == "my-its-task"); } -TEST_CASE("TypeIdHelpers_EdgeCases") -{ - // Single character - REQUIRE(type_to_task_name(std::string_view("A")) == "a"); - - // All uppercase. BC is Bunch Crossing! - // - REQUIRE(type_to_task_name(std::string_view("ABC")) == "a-bc"); - REQUIRE(type_to_task_name(std::string_view("BC")) == "bc"); - - // Mixed with numbers (numbers are not uppercase, so no hyphens before them) - REQUIRE(type_to_task_name(std::string_view("Task123")) == "task123"); -} +//TEST_CASE("TypeIdHelpers_EdgeCases") +//{ +// // Single character +// REQUIRE(type_to_task_name(std::string_view("A")) == "a"); +// +// // All uppercase. BC is Bunch Crossing! +// // +// REQUIRE(type_to_task_name(std::string_view("ABC")) == "a-bc"); +// REQUIRE(type_to_task_name(std::string_view("BC")) == "bc"); +// +// // Mixed with numbers (numbers are not uppercase, so no hyphens before them) +// REQUIRE(type_to_task_name(std::string_view("Task123")) == "task123"); +//} From ee2b995e2450fb5b6a5314b5eca18969e5d260c6 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 3 Feb 2026 14:01:01 +0100 Subject: [PATCH 142/234] Brown paperbag issue with reverted feature. (#15012) --- Framework/Core/test/test_TypeToTaskName.cxx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Framework/Core/test/test_TypeToTaskName.cxx b/Framework/Core/test/test_TypeToTaskName.cxx index af51bc04613f5..cd5a359db0446 100644 --- a/Framework/Core/test/test_TypeToTaskName.cxx +++ b/Framework/Core/test/test_TypeToTaskName.cxx @@ -25,10 +25,10 @@ TEST_CASE("TypeIdHelpers_BasicConversion") TEST_CASE("TypeIdHelpers_AbbreviationConsolidation") { - // Test ALICE detector abbreviations +// Test ALICE detector abbreviations // REQUIRE(type_to_task_name(std::string_view("ITSQA")) == "its-qa"); // REQUIRE(type_to_task_name(std::string_view("TPCQCTask")) == "tpc-qc-task"); - REQUIRE(type_to_task_name(std::string_view("EMCALQATask")) == "emcal-qa-task"); +// REQUIRE(type_to_task_name(std::string_view("EMCALQATask")) == "emcal-qa-task"); // REQUIRE(type_to_task_name(std::string_view("HMPIDTask")) == "hmpid-task"); // REQUIRE(type_to_task_name(std::string_view("ITSTPCTask")) == "its-tpc-task"); // REQUIRE(type_to_task_name(std::string_view("QCFV0Task")) == "qc-fv0-task"); @@ -42,13 +42,13 @@ TEST_CASE("TypeIdHelpers_AbbreviationConsolidation") // REQUIRE(type_to_task_name(std::string_view("QCDAnalysis")) == "qcd-analysis"); //} -TEST_CASE("TypeIdHelpers_ComplexNames") -{ - // Test complex combinations +//TEST_CASE("TypeIdHelpers_ComplexNames") +//{ +// Test complex combinations // REQUIRE(type_to_task_name(std::string_view("ITSQAAnalysisTask")) == "its-qa-analysis-task"); - REQUIRE(type_to_task_name(std::string_view("TPCEMCQCTask")) == "tpc-emc-qc-task"); +// REQUIRE(type_to_task_name(std::string_view("TPCEMCQCTask")) == "tpc-emc-qc-task"); // REQUIRE(type_to_task_name(std::string_view("MyITSTask")) == "my-its-task"); -} +//} //TEST_CASE("TypeIdHelpers_EdgeCases") //{ From ff39f95db1067234eac4ab9dd3681ecba15949bd Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Tue, 3 Feb 2026 15:33:50 +0100 Subject: [PATCH 143/234] Fix and improve TPC Loopers implementation --- Generators/include/Generators/Generator.h | 12 +++++------ Generators/include/Generators/TPCLoopers.h | 2 -- Generators/src/Generator.cxx | 23 ++++++++++++++++++++-- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/Generators/include/Generators/Generator.h b/Generators/include/Generators/Generator.h index 3484601aa42bb..f413aeccfa3ab 100644 --- a/Generators/include/Generators/Generator.h +++ b/Generators/include/Generators/Generator.h @@ -17,10 +17,6 @@ #include "FairGenerator.h" #include "TParticle.h" #include "Generators/Trigger.h" -#ifdef GENERATORS_WITH_TPCLOOPERS -#include "Generators/TPCLoopers.h" -#include "Generators/TPCLoopersParam.h" -#endif #include #include #include @@ -38,6 +34,8 @@ namespace o2 namespace eventgen { +class GenTPCLoopers; // Forward declaration + /*****************************************************************/ /*****************************************************************/ @@ -60,7 +58,7 @@ class Generator : public FairGenerator /** constructor **/ Generator(const Char_t* name, const Char_t* title = "ALICEo2 Generator"); /** destructor **/ - ~Generator() override = default; + ~Generator() override; /** Initialize the generator if needed **/ Bool_t Init() override; @@ -169,9 +167,9 @@ class Generator : public FairGenerator // global static information about (upper limit of) number of events to be generated static unsigned int gTotalNEvents; -#ifdef GENERATORS_WITH_TPCLOOPERS // Loopers generator instance - std::unique_ptr mTPCLoopersGen = nullptr; + o2::eventgen::GenTPCLoopers* mTPCLoopersGen = nullptr; +#ifdef GENERATORS_WITH_TPCLOOPERS bool initTPCLoopersGen(); #endif diff --git a/Generators/include/Generators/TPCLoopers.h b/Generators/include/Generators/TPCLoopers.h index 6a1d3ef262e22..a144a947fc11b 100644 --- a/Generators/include/Generators/TPCLoopers.h +++ b/Generators/include/Generators/TPCLoopers.h @@ -16,14 +16,12 @@ #ifdef GENERATORS_WITH_TPCLOOPERS #include -#endif #include #include #include "TRandom3.h" #include #include "TParticle.h" -#ifdef GENERATORS_WITH_TPCLOOPERS // Static Ort::Env instance for multiple onnx model loading extern Ort::Env global_env; diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 465a8ffb7ee22..ecea311c94de7 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -27,6 +27,10 @@ #include "TGrid.h" #include "CCDB/BasicCCDBManager.h" #include +#ifdef GENERATORS_WITH_TPCLOOPERS +#include "Generators/TPCLoopers.h" +#include "Generators/TPCLoopersParam.h" +#endif namespace o2 { @@ -94,6 +98,19 @@ Generator::Generator(const Char_t* name, const Char_t* title) : FairGenerator(na #endif } +/*****************************************************************/ + +Generator::~Generator() +{ + /** destructor **/ +#ifdef GENERATORS_WITH_TPCLOOPERS + if (mTPCLoopersGen) { + delete mTPCLoopersGen; + mTPCLoopersGen = nullptr; + } +#endif +} + /*****************************************************************/ #ifdef GENERATORS_WITH_TPCLOOPERS bool Generator::initTPCLoopersGen() @@ -171,7 +188,7 @@ bool Generator::initTPCLoopersGen() nclxrate = isAlien[2] || isCCDB[2] ? local_names[2] : nclxrate; try { // Create the TPC loopers generator with the provided parameters - mTPCLoopersGen = std::make_unique(model_pairs, model_compton, poisson, gauss, scaler_pair, scaler_compton); + mTPCLoopersGen = new o2::eventgen::GenTPCLoopers(model_pairs, model_compton, poisson, gauss, scaler_pair, scaler_compton); const auto& intrate = loopersParam.intrate; // Configure the generator with flat gas loopers defined per orbit with clusters/track info // If intrate is negative (default), automatic IR from collisioncontext.root will be used @@ -188,7 +205,9 @@ bool Generator::initTPCLoopersGen() LOG(info) << "TPC Loopers generator initialized successfully"; } catch (const std::exception& e) { LOG(error) << "Failed to initialize TPC Loopers generator: " << e.what(); - mTPCLoopersGen.reset(); + delete mTPCLoopersGen; + mTPCLoopersGen = nullptr; + return kFALSE; } return kTRUE; } From 71634e3b6983e1e54596784828b6fcb145261c9f Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 5 Feb 2026 09:20:34 +0100 Subject: [PATCH 144/234] DPL: Improve message when we do not have enough resources to process. (#15016) --- Framework/Core/src/DataProcessingDevice.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index 8a306c7b96001..ccfb58db7559a 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -1399,12 +1399,12 @@ void DataProcessingDevice::Run() if (schedulingStats.numberOfUnscheduledSinceLastScheduled > 100 || (uv_now(state.loop) - schedulingStats.lastScheduled) > 30000) { O2_SIGNPOST_EVENT_EMIT_WARN(scheduling, sid, "Run", - "Not enough resources to schedule computation. %zu skipped so far. Last scheduled at %zu.", + "Not enough resources to schedule computation. %zu skipped so far. Last scheduled at %zu. Data is not lost and it will be scheduled again.", schedulingStats.numberOfUnscheduledSinceLastScheduled.load(), schedulingStats.lastScheduled.load()); } else { O2_SIGNPOST_EVENT_EMIT(scheduling, sid, "Run", - "Not enough resources to schedule computation. %zu skipped so far. Last scheduled at %zu.", + "Not enough resources to schedule computation. %zu skipped so far. Last scheduled at %zu. Data is not lost and it will be scheduled again.", schedulingStats.numberOfUnscheduledSinceLastScheduled.load(), schedulingStats.lastScheduled.load()); } From bfa44ca0e7a6b8d42cca3ac93f0b7a423869c5a0 Mon Sep 17 00:00:00 2001 From: Gabriele Cimador Date: Fri, 19 Dec 2025 10:59:27 +0100 Subject: [PATCH 145/234] GPU Framework: remove GPUDefParametersDefaults.h and automatically generate GPU parameters using json file and CMake --- .../ITS/tracking/GPU/cuda/CMakeLists.txt | 2 +- GPU/GPUTracking/Base/cuda/CMakeLists.txt | 4 +- GPU/GPUTracking/Base/hip/CMakeLists.txt | 4 +- GPU/GPUTracking/CMakeLists.txt | 21 +- .../Definitions/.clang-format-ignore | 1 + .../Definitions/GPUDefParametersDefaults.h | 589 ------------------ .../Definitions/GPUParameters.json | 582 +++++++++++++++++ GPU/GPUTracking/Definitions/GPUSettingsList.h | 2 +- .../cmake/generateGPUParamHeader.cmake | 37 ++ .../cmake/gpu_param_header_generator.cmake | 105 ++++ GPU/documentation/build-O2.md | 2 +- dependencies/FindO2GPU.cmake | 43 +- log.txt | 0 13 files changed, 777 insertions(+), 615 deletions(-) create mode 100644 GPU/GPUTracking/Definitions/.clang-format-ignore delete mode 100644 GPU/GPUTracking/Definitions/GPUDefParametersDefaults.h create mode 100644 GPU/GPUTracking/Definitions/GPUParameters.json create mode 100644 GPU/GPUTracking/cmake/generateGPUParamHeader.cmake create mode 100644 GPU/GPUTracking/cmake/gpu_param_header_generator.cmake create mode 100644 log.txt diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/CMakeLists.txt b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/CMakeLists.txt index 1f6a046a81350..e38dbb1ef20e8 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/CMakeLists.txt @@ -35,5 +35,5 @@ if(CUDA_ENABLED) set_property(TARGET ${targetName} PROPERTY CUDA_SEPARABLE_COMPILATION ON) target_compile_definitions(${targetName} PRIVATE $) - set_target_cuda_arch(${targetName}) + set_target_gpu_arch("CUDA" ${targetName}) endif() diff --git a/GPU/GPUTracking/Base/cuda/CMakeLists.txt b/GPU/GPUTracking/Base/cuda/CMakeLists.txt index 05ed091eb83ea..226bacbf88157 100644 --- a/GPU/GPUTracking/Base/cuda/CMakeLists.txt +++ b/GPU/GPUTracking/Base/cuda/CMakeLists.txt @@ -74,7 +74,7 @@ add_custom_command( COMMAND cat ${GPUDIR}/Base/GPUStdSystemHeaders.h >> ${GPU_RTC_BIN}.src COMMAND ${CMAKE_CUDA_COMPILER} ${GPU_RTC_DEFINES} ${GPU_RTC_INCLUDES} -std=c++${CMAKE_CUDA_STANDARD} -D__CUDA_ARCH__=${RTC_CUDA_ARCH} -Wno-deprecated-gpu-targets -D__CUDACC__ -x c++ -M -MD -MT ${GPU_RTC_BIN}.src -MF ${GPU_RTC_BIN}.src.d ${GPU_RTC_SRC} COMMAND ${CMAKE_CUDA_COMPILER} ${GPU_RTC_DEFINES} ${GPU_RTC_INCLUDES} -std=c++${CMAKE_CUDA_STANDARD} -D__CUDA_ARCH__=${RTC_CUDA_ARCH} -Wno-deprecated-gpu-targets -D__CUDACC__ -x c++ -E -Xcompiler "-nostdinc -P" ${GPU_RTC_SRC} >> ${GPU_RTC_BIN}.src - DEPENDS ${GPU_RTC_SRC} ${GPUDIR}/Base/GPUStdSystemHeaders.h ${GPUDIR}/Base/cuda/GPUReconstructionCUDAIncludesSystem.h ${GPUDIR}/Base/GPUStdSystemHeaders.h + DEPENDS ${GPU_RTC_SRC} ${GPUDIR}/Base/GPUStdSystemHeaders.h ${GPUDIR}/Base/cuda/GPUReconstructionCUDAIncludesSystem.h ${GPUDIR}/Base/GPUStdSystemHeaders.h GPU_PARAM_HEADER_AUTO_ALL DEPFILE ${GPU_RTC_BIN}.src.d COMMAND_EXPAND_LISTS COMMENT "Preparing CUDA RTC source file ${GPU_RTC_BIN}.src" @@ -149,7 +149,7 @@ endif() # Setting target architecture and adding GPU libraries target_link_libraries(${targetName} PRIVATE cuda cudart) -set_target_cuda_arch(${targetName}) +set_target_gpu_arch("CUDA" ${targetName}) #target_link_options(${targetName} PRIVATE "LINKER:--version-script=${CMAKE_CURRENT_SOURCE_DIR}/version_script.ld") #set_target_properties(${targetName} PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/version_script.ld) diff --git a/GPU/GPUTracking/Base/hip/CMakeLists.txt b/GPU/GPUTracking/Base/hip/CMakeLists.txt index 501509d8dfcf6..d148e376abca9 100644 --- a/GPU/GPUTracking/Base/hip/CMakeLists.txt +++ b/GPU/GPUTracking/Base/hip/CMakeLists.txt @@ -125,7 +125,7 @@ add_custom_command( COMMAND cat ${GPUDIR}/Base/hip/GPUReconstructionHIPIncludesSystem.h | grep -v GPUStdSystemHeaders.h >> ${GPU_RTC_BIN}.src COMMAND cat ${GPUDIR}/Base/GPUStdSystemHeaders.h >> ${GPU_RTC_BIN}.src COMMAND ${CMAKE_HIP_COMPILER} ${GPU_RTC_DEFINES} ${GPU_RTC_INCLUDES} -std=c++${CMAKE_HIP_STANDARD} -D__HIPCC__ -D__HIP_DEVICE_COMPILE__ -x c++ -nostdinc -E -P ${GPU_RTC_SRC} -MD -MT ${GPU_RTC_BIN}.src -MF ${GPU_RTC_BIN}.src.d >> ${GPU_RTC_BIN}.src - DEPENDS ${GPU_RTC_SRC} ${GPUDIR}/Base/GPUStdSystemHeaders.h ${GPUDIR}/Base/hip/GPUReconstructionHIPIncludesSystem.h ${GPUDIR}/Base/GPUStdSystemHeaders.h ${MODULE}_HIPIFIED + DEPENDS ${GPU_RTC_SRC} ${GPUDIR}/Base/GPUStdSystemHeaders.h ${GPUDIR}/Base/hip/GPUReconstructionHIPIncludesSystem.h ${GPUDIR}/Base/GPUStdSystemHeaders.h ${MODULE}_HIPIFIED GPU_PARAM_HEADER_AUTO_ALL DEPFILE ${GPU_RTC_BIN}.src.d COMMAND_EXPAND_LISTS COMMENT "Preparing HIP RTC source file ${GPU_RTC_BIN}.src" @@ -219,7 +219,7 @@ endif() # Setting target architecture and adding GPU libraries target_link_libraries(${targetName} PRIVATE hip::host hip::device hip::hipcub roc::rocthrust) -set_target_hip_arch(${targetName}) +set_target_gpu_arch("HIP" ${targetName}) target_link_libraries(${MODULE}_CXX PRIVATE TBB::tbb) diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index 9e9344108ccfb..a2d91b6ed4c5e 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -107,6 +107,12 @@ set(SRCS_NO_H SectorTracker/GPUTPCTrackerDump.cxx Global/GPUChainTrackingDebugAndProfiling.cxx Global/GPUChainTrackingIO.cxx) +set(ON_THE_FLY_DIR ${CMAKE_CURRENT_BINARY_DIR}/include_gpu_onthefly) +file(MAKE_DIRECTORY ${ON_THE_FLY_DIR}) +include(cmake/generateGPUParamHeader.cmake) +set(GPU_DEFAULT_PARAMS_HEADER ${ON_THE_FLY_DIR}/GPUDefParametersDefaults.h) +generate_gpu_param_header("AUTO" ${GPU_DEFAULT_PARAMS_HEADER}) # generate header with default GPU parameters, arch selected by CMake variables + set(HDRS_INSTALL ${HDRS_CINT_O2} ${HDRS_CINT_DATATYPES} @@ -135,9 +141,9 @@ set(HDRS_INSTALL DataTypes/GPUO2ExternalUser.h Debug/GPUROOTDump.h Definitions/GPUDefConstantsAndSettings.h + ${GPU_DEFAULT_PARAMS_HEADER} Definitions/GPUDefParametersWrapper.h Definitions/GPUDefParametersConstants.h - Definitions/GPUDefParametersDefaults.h Definitions/GPUDef.h Definitions/GPUDefMacros.h Definitions/GPULogging.h @@ -239,8 +245,6 @@ set(TEMPLATE_HEADER_LIST Base/GPUReconstructionKernelList.template.h Definitions/GPUDefParametersLoad.template.inc) set(GENERATED_HEADERS_LIST "") -set(ON_THE_FLY_DIR ${CMAKE_CURRENT_BINARY_DIR}/include_gpu_onthefly) -file(MAKE_DIRECTORY ${ON_THE_FLY_DIR}) foreach(TEMPLATE_FILE ${TEMPLATE_HEADER_LIST}) get_filename_component(OUTPUT_FILE_NAME ${TEMPLATE_FILE} NAME) string(REPLACE ".template" "" OUTPUT_FILE_NAME ${OUTPUT_FILE_NAME}) @@ -286,6 +290,7 @@ set(HDRS_CINT_DATATYPES ${HDRS_CINT_DATATYPES} ${HDRS_TMP}) unset(HDRS_TMP) set(INCDIRS + ${ON_THE_FLY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/Definitions ${CMAKE_CURRENT_SOURCE_DIR}/DataTypes @@ -302,14 +307,14 @@ set(INCDIRS ${CMAKE_CURRENT_SOURCE_DIR}/Refit ${CMAKE_CURRENT_SOURCE_DIR}/Debug ${CMAKE_CURRENT_SOURCE_DIR}/DataCompression - ${CMAKE_CURRENT_SOURCE_DIR}/TPCClusterFinder - ${ON_THE_FLY_DIR}) + ${CMAKE_CURRENT_SOURCE_DIR}/TPCClusterFinder) # Main CMake part for O2 if(ALIGPU_BUILD_TYPE STREQUAL "O2") o2_add_library(GPUDataTypes TARGETVARNAME targetName PUBLIC_INCLUDE_DIRECTORIES . + ${ON_THE_FLY_DIR} Definitions DataTypes PUBLIC_LINK_LIBRARIES O2::GPUUtils @@ -409,15 +414,17 @@ set(GPU_CONST_PARAM_ARCHITECTUES AMPERE TURING VEGA MI100) set(GPU_CONST_PARAM_FILES "") foreach(GPU_ARCH ${GPU_CONST_PARAM_ARCHITECTUES}) set(PARAMFILE ${CMAKE_CURRENT_BINARY_DIR}/genGPUArch/gpu_const_param_${GPU_ARCH}.par) + set(GPU_ARCH_PARAMS_HEADER ${CMAKE_CURRENT_BINARY_DIR}/genGPUArch/GPUDefParametersDefaults_${GPU_ARCH}.h) + generate_gpu_param_header(${GPU_ARCH} ${GPU_ARCH_PARAMS_HEADER}) add_custom_command( OUTPUT ${PARAMFILE} COMMAND bash -c - "echo -e '#define GPUCA_GPUTYPE_${GPU_ARCH}\\n#define PARAMETER_FILE \"GPUDefParametersDefaults.h\"\\ngInterpreter->AddIncludePath(\"${CMAKE_CURRENT_SOURCE_DIR}/Definitions\");\\ngInterpreter->AddIncludePath(\"${ON_THE_FLY_DIR}\");\\n.x ${CMAKE_CURRENT_SOURCE_DIR}/Standalone/tools/dumpGPUDefParam.C(\"${PARAMFILE}\")\\n.q\\n'" + "echo -e '#define GPUCA_GPUTYPE_${GPU_ARCH}\\n#define PARAMETER_FILE \"${GPU_ARCH_PARAMS_HEADER}\"\\ngInterpreter->AddIncludePath(\"${CMAKE_CURRENT_SOURCE_DIR}/Definitions\");\\ngInterpreter->AddIncludePath(\"${ON_THE_FLY_DIR}\");\\n.x ${CMAKE_CURRENT_SOURCE_DIR}/Standalone/tools/dumpGPUDefParam.C(\"${PARAMFILE}\")\\n.q\\n'" | root -l -b > /dev/null VERBATIM WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/genGPUArch MAIN_DEPENDENCY Standalone/tools/dumpGPUDefParam.C - DEPENDS Definitions/GPUDefParametersDefaults.h + DEPENDS ${GPU_ARCH_PARAMS_HEADER} ${ON_THE_FLY_DIR}/GPUDefParametersLoadPrepare.h ${ON_THE_FLY_DIR}/GPUDefParametersLoad.inc COMMENT "Generating GPU parameter set for architecture ${GPU_ARCH}") diff --git a/GPU/GPUTracking/Definitions/.clang-format-ignore b/GPU/GPUTracking/Definitions/.clang-format-ignore new file mode 100644 index 0000000000000..5ffee2498bd7e --- /dev/null +++ b/GPU/GPUTracking/Definitions/.clang-format-ignore @@ -0,0 +1 @@ +GPUParameters.json diff --git a/GPU/GPUTracking/Definitions/GPUDefParametersDefaults.h b/GPU/GPUTracking/Definitions/GPUDefParametersDefaults.h deleted file mode 100644 index 1be881ee6323e..0000000000000 --- a/GPU/GPUTracking/Definitions/GPUDefParametersDefaults.h +++ /dev/null @@ -1,589 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUDefParametersDefaults.h -/// \author David Rohr - -// This file contains compile-time constants affecting the GPU performance. - -#if !defined(GPUDEFPARAMETERSDEFAULTS_H) -#define GPUDEFPARAMETERSDEFAULTS_H -// clang-format off - -// Launch bound definition, 3 optional parameters: maxThreads per block, minBlocks per multiprocessor, force number of blocks (not passed to compiler as launch bounds) - -// GPU Run Configuration -#if defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_NO_LAUNCH_BOUNDS) // Avoid including for RTC generation besides normal include protection. - // GPU-architecture-dependent default settings - #if defined(GPUCA_GPUTYPE_MI100) - #define GPUCA_WARP_SIZE 64 - #define GPUCA_PAR_AMD_EUS_PER_CU 4 - #define GPUCA_THREAD_COUNT_DEFAULT 256 - #define GPUCA_LB_GPUTPCCreateTrackingData 256, 7 - #define GPUCA_LB_GPUTPCStartHitsSorter 1024, 5 - #define GPUCA_LB_GPUTPCStartHitsFinder 1024, 2 - #define GPUCA_LB_GPUTPCTrackletConstructor 768, 8 - #define GPUCA_LB_GPUTPCTrackletSelector 384, 5 - #define GPUCA_LB_GPUTPCNeighboursFinder 192, 8 - #define GPUCA_LB_GPUTPCNeighboursCleaner 128, 5 - #define GPUCA_LB_GPUTPCExtrapolationTracking 256, 7 - #define GPUCA_LB_GPUTPCCFDecodeZS 64, 4 - #define GPUCA_LB_GPUTPCCFDecodeZSLink GPUCA_WARP_SIZE - #define GPUCA_LB_GPUTPCCFDecodeZSDenseLink GPUCA_WARP_SIZE, 4 - #define GPUCA_LB_GPUTPCCFGather 1024, 5 - #define GPUCA_LB_GPUTPCGMMergerTrackFit 192, 2 - #define GPUCA_LB_GPUTPCGMMergerFollowLoopers 256, 5 - #define GPUCA_LB_GPUTPCGMMergerSectorRefit 64, 4 - #define GPUCA_LB_GPUTPCGMMergerUnpackResetIds 256 - #define GPUCA_LB_GPUTPCGMMergerUnpackGlobal 256 - #define GPUCA_LB_GPUTPCGMMergerResolve_step0 512 - #define GPUCA_LB_GPUTPCGMMergerResolve_step1 512 - #define GPUCA_LB_GPUTPCGMMergerResolve_step2 512 - #define GPUCA_LB_GPUTPCGMMergerResolve_step3 512 - #define GPUCA_LB_GPUTPCGMMergerResolve_step4 512 - #define GPUCA_LB_GPUTPCGMMergerClearLinks 256 - #define GPUCA_LB_GPUTPCGMMergerMergeWithinPrepare 256 - #define GPUCA_LB_GPUTPCGMMergerMergeSectorsPrepare 256 - #define GPUCA_LB_GPUTPCGMMergerMergeBorders_step0 512 - #define GPUCA_LB_GPUTPCGMMergerMergeBorders_step2 512 - #define GPUCA_LB_GPUTPCGMMergerMergeCE 512 - #define GPUCA_LB_GPUTPCGMMergerLinkExtrapolatedTracks 256 - #define GPUCA_LB_GPUTPCGMMergerCollect 768, 1 - #define GPUCA_LB_GPUTPCGMMergerSortTracksPrepare 256 - #define GPUCA_LB_GPUTPCGMMergerPrepareForFit_step0 256 - #define GPUCA_LB_GPUTPCGMMergerPrepareForFit_step1 256 - #define GPUCA_LB_GPUTPCGMMergerPrepareForFit_step2 256 - #define GPUCA_LB_GPUTPCGMMergerFinalize_0 256 - #define GPUCA_LB_GPUTPCGMMergerFinalize_1 256 - #define GPUCA_LB_GPUTPCGMMergerFinalize_2 256 - #define GPUCA_LB_GPUTPCCompressionKernels_step0attached 128, 1 - #define GPUCA_LB_GPUTPCCompressionKernels_step1unattached 512, 2 - #define GPUCA_LB_GPUTPCDecompressionKernels_step0attached 128, 2 - #define GPUCA_LB_GPUTPCDecompressionKernels_step1unattached 64, 2 - #define GPUCA_LB_GPUTPCCFCheckPadBaseline 576, 2 - #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillIndexMap 512 - #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillFromDigits 512 - #define GPUCA_LB_GPUTPCCFChargeMapFiller_findFragmentStart 512 - #define GPUCA_LB_GPUTPCCFPeakFinder 512, 9 - #define GPUCA_LB_GPUTPCCFNoiseSuppression 512 - #define GPUCA_LB_GPUTPCCFDeconvolution 512, 5 - #define GPUCA_LB_GPUTPCCFClusterizer 448, 3 - #define GPUCA_LB_COMPRESSION_GATHER 1024 - #define GPUCA_PAR_NEIGHBOURS_FINDER_MAX_NNEIGHUP 10 - #define PAR_NEIGHBOURS_FINDER_UNROLL_GLOBAL 4 - #define GPUCA_PAR_NEIGHBOURS_FINDER_UNROLL_SHARED 0 - #define GPUCA_PAR_TRACKLET_SELECTOR_HITS_REG_SIZE 9 - #define GPUCA_PAR_ALTERNATE_BORDER_SORT 1 - #define GPUCA_PAR_SORT_BEFORE_FIT 1 - #define GPUCA_PAR_NO_ATOMIC_PRECHECK 1 - #define GPUCA_PAR_DEDX_STORAGE_TYPE uint16_t - #define GPUCA_PAR_MERGER_INTERPOLATION_ERROR_TYPE half - #define GPUCA_PAR_COMP_GATHER_KERNEL 4 - #define GPUCA_PAR_COMP_GATHER_MODE 3 - #elif defined(GPUCA_GPUTYPE_VEGA) - #define GPUCA_WARP_SIZE 64 - #define GPUCA_PAR_AMD_EUS_PER_CU 4 - #define GPUCA_THREAD_COUNT_DEFAULT 256 - #define GPUCA_LB_GPUTPCCreateTrackingData 192, 2 - #define GPUCA_LB_GPUTPCStartHitsSorter 512, 7 - #define GPUCA_LB_GPUTPCStartHitsFinder 1024, 7 - #define GPUCA_LB_GPUTPCTrackletConstructor 512, 10 - #define GPUCA_LB_GPUTPCTrackletSelector 192, 10 - #define GPUCA_LB_GPUTPCNeighboursFinder 960, 8 - #define GPUCA_LB_GPUTPCNeighboursCleaner 384, 9 - #define GPUCA_LB_GPUTPCExtrapolationTracking 256, 2 - #define GPUCA_LB_GPUTPCCFDecodeZS 64, 1 - #define GPUCA_LB_GPUTPCCFDecodeZSLink GPUCA_WARP_SIZE - #define GPUCA_LB_GPUTPCCFDecodeZSDenseLink GPUCA_WARP_SIZE, 14 - #define GPUCA_LB_GPUTPCCFGather 1024, 1 - #define GPUCA_LB_GPUTPCGMMergerTrackFit 64, 7 - #define GPUCA_LB_GPUTPCGMMergerFollowLoopers 256, 4 - #define GPUCA_LB_GPUTPCGMMergerSectorRefit 256, 2 - #define GPUCA_LB_GPUTPCGMMergerUnpackResetIds 256 - #define GPUCA_LB_GPUTPCGMMergerUnpackGlobal 256 - #define GPUCA_LB_GPUTPCGMMergerResolve_step0 256 - #define GPUCA_LB_GPUTPCGMMergerResolve_step1 256 - #define GPUCA_LB_GPUTPCGMMergerResolve_step2 256 - #define GPUCA_LB_GPUTPCGMMergerResolve_step3 256 - #define GPUCA_LB_GPUTPCGMMergerResolve_step4 256 - #define GPUCA_LB_GPUTPCGMMergerClearLinks 256 - #define GPUCA_LB_GPUTPCGMMergerMergeWithinPrepare 256 - #define GPUCA_LB_GPUTPCGMMergerMergeSectorsPrepare 256 - #define GPUCA_LB_GPUTPCGMMergerMergeBorders_step0 256 - #define GPUCA_LB_GPUTPCGMMergerMergeBorders_step2 256 - #define GPUCA_LB_GPUTPCGMMergerMergeCE 256 - #define GPUCA_LB_GPUTPCGMMergerLinkExtrapolatedTracks 256 - #define GPUCA_LB_GPUTPCGMMergerCollect 1024, 1 - #define GPUCA_LB_GPUTPCGMMergerSortTracksPrepare 256 - #define GPUCA_LB_GPUTPCGMMergerPrepareForFit_step0 256 - #define GPUCA_LB_GPUTPCGMMergerPrepareForFit_step1 256 - #define GPUCA_LB_GPUTPCGMMergerPrepareForFit_step2 256 - #define GPUCA_LB_GPUTPCGMMergerFinalize_0 256 - #define GPUCA_LB_GPUTPCGMMergerFinalize_1 256 - #define GPUCA_LB_GPUTPCGMMergerFinalize_2 256 - #define GPUCA_LB_GPUTPCCompressionKernels_step0attached 64, 2 - #define GPUCA_LB_GPUTPCCompressionKernels_step1unattached 512, 2 - #define GPUCA_LB_GPUTPCDecompressionKernels_step0attached 128, 2 - #define GPUCA_LB_GPUTPCDecompressionKernels_step1unattached 64, 2 - #define GPUCA_LB_GPUTPCCFCheckPadBaseline 576, 2 - #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillIndexMap 512 - #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillFromDigits 512 - #define GPUCA_LB_GPUTPCCFChargeMapFiller_findFragmentStart 512 - #define GPUCA_LB_GPUTPCCFPeakFinder 512, 4 - #define GPUCA_LB_GPUTPCCFNoiseSuppression 512 - #define GPUCA_LB_GPUTPCCFDeconvolution 512, 5 - #define GPUCA_LB_GPUTPCCFClusterizer 512, 2 - #define GPUCA_LB_COMPRESSION_GATHER 1024 - #define GPUCA_PAR_NEIGHBOURS_FINDER_MAX_NNEIGHUP 4 - #define GPUCA_PAR_NEIGHBOURS_FINDER_UNROLL_GLOBAL 2 - #define GPUCA_PAR_NEIGHBOURS_FINDER_UNROLL_SHARED 0 - #define GPUCA_PAR_TRACKLET_SELECTOR_HITS_REG_SIZE 27 - #define GPUCA_PAR_ALTERNATE_BORDER_SORT 1 - #define GPUCA_PAR_SORT_BEFORE_FIT 1 - #define GPUCA_PAR_NO_ATOMIC_PRECHECK 1 - #define GPUCA_PAR_DEDX_STORAGE_TYPE uint16_t - #define GPUCA_PAR_MERGER_INTERPOLATION_ERROR_TYPE half - #define GPUCA_PAR_COMP_GATHER_KERNEL 4 - #define GPUCA_PAR_COMP_GATHER_MODE 3 - #elif defined(GPUCA_GPUTYPE_AMPERE) - #define GPUCA_WARP_SIZE 32 - #define GPUCA_THREAD_COUNT_DEFAULT 512 - #define GPUCA_LB_GPUTPCCreateTrackingData 384 - #define GPUCA_LB_GPUTPCStartHitsSorter 512, 1 - #define GPUCA_LB_GPUTPCStartHitsFinder 512 - #define GPUCA_LB_GPUTPCTrackletConstructor 256, 2 // best single-kernel: 128, 4 - #define GPUCA_LB_GPUTPCTrackletSelector 192, 3 // best single-kernel: 128, 4 - #define GPUCA_LB_GPUTPCNeighboursFinder 640, 1 // best single-kernel: 768, 1 - #define GPUCA_LB_GPUTPCNeighboursCleaner 512 - #define GPUCA_LB_GPUTPCExtrapolationTracking 128, 4 - #define GPUCA_LB_GPUTPCCFDecodeZS 64, 10 - #define GPUCA_LB_GPUTPCCFDecodeZSLink GPUCA_WARP_SIZE - #define GPUCA_LB_GPUTPCCFDecodeZSDenseLink GPUCA_WARP_SIZE - #define GPUCA_LB_GPUTPCCFGather 1024, 1 - #define GPUCA_LB_GPUTPCGMMergerTrackFit 64, 4 - #define GPUCA_LB_GPUTPCGMMergerFollowLoopers 64, 12 - #define GPUCA_LB_GPUTPCGMMergerSectorRefit 32, 6 - #define GPUCA_LB_GPUTPCGMMergerUnpackResetIds 256 - #define GPUCA_LB_GPUTPCGMMergerUnpackGlobal 256 - #define GPUCA_LB_GPUTPCGMMergerResolve_step0 256 - #define GPUCA_LB_GPUTPCGMMergerResolve_step1 256 - #define GPUCA_LB_GPUTPCGMMergerResolve_step2 256 - #define GPUCA_LB_GPUTPCGMMergerResolve_step3 256 - #define GPUCA_LB_GPUTPCGMMergerResolve_step4 256, 4 - #define GPUCA_LB_GPUTPCGMMergerClearLinks 256 - #define GPUCA_LB_GPUTPCGMMergerMergeWithinPrepare 256 - #define GPUCA_LB_GPUTPCGMMergerMergeSectorsPrepare 256, 2 - #define GPUCA_LB_GPUTPCGMMergerMergeBorders_step0 192 - #define GPUCA_LB_GPUTPCGMMergerMergeBorders_step2 64, 2 - #define GPUCA_LB_GPUTPCGMMergerMergeCE 256 - #define GPUCA_LB_GPUTPCGMMergerLinkExtrapolatedTracks 256 - #define GPUCA_LB_GPUTPCGMMergerCollect 256, 2 - #define GPUCA_LB_GPUTPCGMMergerSortTracksPrepare 256 - #define GPUCA_LB_GPUTPCGMMergerPrepareForFit_step0 256 - #define GPUCA_LB_GPUTPCGMMergerPrepareForFit_step1 256 - #define GPUCA_LB_GPUTPCGMMergerPrepareForFit_step2 256 - #define GPUCA_LB_GPUTPCGMMergerFinalize_0 256 - #define GPUCA_LB_GPUTPCGMMergerFinalize_1 256 - #define GPUCA_LB_GPUTPCGMMergerFinalize_2 256 - #define GPUCA_LB_GPUTPCCompressionKernels_step0attached 64, 2 - #define GPUCA_LB_GPUTPCCompressionKernels_step1unattached 512, 3 - #define GPUCA_LB_GPUTPCDecompressionKernels_step0attached 32, 1 - #define GPUCA_LB_GPUTPCDecompressionKernels_step1unattached 32, 1 - #define GPUCA_LB_GPUTPCCFCheckPadBaseline 576,2 - #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillIndexMap 448 - #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillFromDigits 448 - #define GPUCA_LB_GPUTPCCFChargeMapFiller_findFragmentStart 448 - #define GPUCA_LB_GPUTPCCFPeakFinder 128 - #define GPUCA_LB_GPUTPCCFNoiseSuppression 448 - #define GPUCA_LB_GPUTPCCFDeconvolution 384 - #define GPUCA_LB_GPUTPCCFClusterizer 448 - #define GPUCA_LB_COMPRESSION_GATHER 1024 - #define GPUCA_PAR_NEIGHBOURS_FINDER_MAX_NNEIGHUP 4 - #define GPUCA_PAR_TRACKLET_SELECTOR_HITS_REG_SIZE 20 - #define GPUCA_PAR_ALTERNATE_BORDER_SORT 1 - #define GPUCA_PAR_SORT_BEFORE_FIT 1 - #define GPUCA_PAR_NO_ATOMIC_PRECHECK 1 - #define GPUCA_PAR_DEDX_STORAGE_TYPE uint16_t - #define GPUCA_PAR_MERGER_INTERPOLATION_ERROR_TYPE half - #define GPUCA_PAR_COMP_GATHER_KERNEL 4 - #define GPUCA_PAR_COMP_GATHER_MODE 3 - #elif defined(GPUCA_GPUTYPE_TURING) - #define GPUCA_WARP_SIZE 32 - #define GPUCA_THREAD_COUNT_DEFAULT 512 - #define GPUCA_LB_GPUTPCCreateTrackingData 256 - #define GPUCA_LB_GPUTPCStartHitsSorter 512, 1 - #define GPUCA_LB_GPUTPCStartHitsFinder 512 - #define GPUCA_LB_GPUTPCTrackletConstructor 256, 2 - #define GPUCA_LB_GPUTPCTrackletSelector 192, 3 - #define GPUCA_LB_GPUTPCNeighboursFinder 640, 1 - #define GPUCA_LB_GPUTPCNeighboursCleaner 512 - #define GPUCA_LB_GPUTPCExtrapolationTracking 192, 2 - #define GPUCA_LB_GPUTPCCFDecodeZS 64, 8 - #define GPUCA_LB_GPUTPCCFDecodeZSLink GPUCA_WARP_SIZE - #define GPUCA_LB_GPUTPCCFDecodeZSDenseLink GPUCA_WARP_SIZE - #define GPUCA_LB_GPUTPCCFGather 1024, 1 - #define GPUCA_LB_GPUTPCGMMergerTrackFit 32, 8 - #define GPUCA_LB_GPUTPCGMMergerFollowLoopers 128, 4 - #define GPUCA_LB_GPUTPCGMMergerSectorRefit 64, 5 - #define GPUCA_LB_GPUTPCGMMergerUnpackResetIds 256 - #define GPUCA_LB_GPUTPCGMMergerUnpackGlobal 256 - #define GPUCA_LB_GPUTPCGMMergerResolve_step0 256 - #define GPUCA_LB_GPUTPCGMMergerResolve_step1 256 - #define GPUCA_LB_GPUTPCGMMergerResolve_step2 256 - #define GPUCA_LB_GPUTPCGMMergerResolve_step3 256 - #define GPUCA_LB_GPUTPCGMMergerResolve_step4 256, 4 - #define GPUCA_LB_GPUTPCGMMergerClearLinks 256 - #define GPUCA_LB_GPUTPCGMMergerMergeWithinPrepare 256 - #define GPUCA_LB_GPUTPCGMMergerMergeSectorsPrepare 256, 2 - #define GPUCA_LB_GPUTPCGMMergerMergeBorders_step0 192 - #define GPUCA_LB_GPUTPCGMMergerMergeBorders_step2 256 - #define GPUCA_LB_GPUTPCGMMergerMergeCE 256 - #define GPUCA_LB_GPUTPCGMMergerLinkExtrapolatedTracks 256 - #define GPUCA_LB_GPUTPCGMMergerCollect 128, 2 - #define GPUCA_LB_GPUTPCGMMergerSortTracksPrepare 256 - #define GPUCA_LB_GPUTPCGMMergerPrepareForFit_step0 256 - #define GPUCA_LB_GPUTPCGMMergerPrepareForFit_step1 256 - #define GPUCA_LB_GPUTPCGMMergerPrepareForFit_step2 256 - #define GPUCA_LB_GPUTPCGMMergerFinalize_0 256 - #define GPUCA_LB_GPUTPCGMMergerFinalize_1 256 - #define GPUCA_LB_GPUTPCGMMergerFinalize_2 256 - #define GPUCA_LB_GPUTPCCompressionKernels_step0attached 128 - #define GPUCA_LB_GPUTPCCompressionKernels_step1unattached 512, 2 - #define GPUCA_LB_GPUTPCDecompressionKernels_step0attached 32, 1 - #define GPUCA_LB_GPUTPCDecompressionKernels_step1unattached 32, 1 - #define GPUCA_LB_COMPRESSION_GATHER 1024 - #define GPUCA_PAR_NEIGHBOURS_FINDER_MAX_NNEIGHUP 4 - #define GPUCA_PAR_TRACKLET_SELECTOR_HITS_REG_SIZE 20 - #define GPUCA_PAR_ALTERNATE_BORDER_SORT 1 - #define GPUCA_PAR_SORT_BEFORE_FIT 1 - #define GPUCA_PAR_NO_ATOMIC_PRECHECK 1 - #define GPUCA_PAR_COMP_GATHER_KERNEL 4 - #define GPUCA_PAR_COMP_GATHER_MODE 3 - #define GPUCA_PAR_DEDX_STORAGE_TYPE uint16_t - #define GPUCA_PAR_MERGER_INTERPOLATION_ERROR_TYPE half - #elif defined(GPUCA_GPUTYPE_OPENCL) - #else - #error GPU TYPE NOT SET - #endif - - // Default settings for GPU, if not already set for selected GPU type - #ifndef GPUCA_WARP_SIZE - #define GPUCA_WARP_SIZE 32 - #endif - #ifndef GPUCA_PAR_AMD_EUS_PER_CU - #define GPUCA_PAR_AMD_EUS_PER_CU 0 - #endif - #ifndef GPUCA_THREAD_COUNT_DEFAULT - #define GPUCA_THREAD_COUNT_DEFAULT 256 - #endif - #ifndef GPUCA_LB_GPUTPCCreateTrackingData - #define GPUCA_LB_GPUTPCCreateTrackingData 256 - #endif - #ifndef GPUCA_LB_GPUTPCTrackletConstructor - #define GPUCA_LB_GPUTPCTrackletConstructor 256 - #endif - #ifndef GPUCA_LB_GPUTPCTrackletSelector - #define GPUCA_LB_GPUTPCTrackletSelector 256 - #endif - #ifndef GPUCA_LB_GPUTPCNeighboursFinder - #define GPUCA_LB_GPUTPCNeighboursFinder 256 - #endif - #ifndef GPUCA_LB_GPUTPCNeighboursCleaner - #define GPUCA_LB_GPUTPCNeighboursCleaner 256 - #endif - #ifndef GPUCA_LB_GPUTPCExtrapolationTracking - #define GPUCA_LB_GPUTPCExtrapolationTracking 256 - #endif - #ifndef GPUCA_LB_GPUTRDTrackerKernels_gpuVersion - #define GPUCA_LB_GPUTRDTrackerKernels_gpuVersion 512 - #endif - #ifndef GPUCA_LB_GPUTPCCreateOccupancyMap_fill - #define GPUCA_LB_GPUTPCCreateOccupancyMap_fill 256 - #endif - #ifndef GPUCA_LB_GPUTPCCreateOccupancyMap_fold - #define GPUCA_LB_GPUTPCCreateOccupancyMap_fold 256 - #endif - #ifndef GPUCA_LB_GPUTRDTrackerKernels_o2Version - #define GPUCA_LB_GPUTRDTrackerKernels_o2Version 512 - #endif - #ifndef GPUCA_LB_GPUTPCCompressionKernels_step0attached - #define GPUCA_LB_GPUTPCCompressionKernels_step0attached 256 - #endif - #ifndef GPUCA_LB_GPUTPCCompressionKernels_step1unattached - #define GPUCA_LB_GPUTPCCompressionKernels_step1unattached 256 - #endif - #ifndef GPUCA_LB_GPUTPCDecompressionKernels_step0attached - #define GPUCA_LB_GPUTPCDecompressionKernels_step0attached 256 - #endif - #ifndef GPUCA_LB_GPUTPCDecompressionKernels_step1unattached - #define GPUCA_LB_GPUTPCDecompressionKernels_step1unattached 256 - #endif - #ifndef GPUCA_LB_GPUTPCDecompressionUtilKernels_sortPerSectorRow - #define GPUCA_LB_GPUTPCDecompressionUtilKernels_sortPerSectorRow 256 - #endif - #ifndef GPUCA_LB_GPUTPCDecompressionUtilKernels_countFilteredClusters - #define GPUCA_LB_GPUTPCDecompressionUtilKernels_countFilteredClusters 256 - #endif - #ifndef GPUCA_LB_GPUTPCDecompressionUtilKernels_storeFilteredClusters - #define GPUCA_LB_GPUTPCDecompressionUtilKernels_storeFilteredClusters 256 - #endif - #ifndef GPUCA_LB_GPUTPCCFDecodeZS - #define GPUCA_LB_GPUTPCCFDecodeZS 128, 4 - #endif - #ifndef GPUCA_LB_GPUTPCCFDecodeZSLink - #define GPUCA_LB_GPUTPCCFDecodeZSLink GPUCA_WARP_SIZE - #endif - #ifndef GPUCA_LB_GPUTPCCFDecodeZSDenseLink - #define GPUCA_LB_GPUTPCCFDecodeZSDenseLink GPUCA_WARP_SIZE - #endif - #ifndef GPUCA_LB_GPUTPCCFGather - #define GPUCA_LB_GPUTPCCFGather 1024, 1 - #endif - #ifndef GPUCA_LB_COMPRESSION_GATHER - #define GPUCA_LB_COMPRESSION_GATHER 1024 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerTrackFit - #define GPUCA_LB_GPUTPCGMMergerTrackFit 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerFollowLoopers - #define GPUCA_LB_GPUTPCGMMergerFollowLoopers 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerSectorRefit - #define GPUCA_LB_GPUTPCGMMergerSectorRefit 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerUnpackResetIds - #define GPUCA_LB_GPUTPCGMMergerUnpackResetIds 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerUnpackGlobal - #define GPUCA_LB_GPUTPCGMMergerUnpackGlobal 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerResolve_step0 - #define GPUCA_LB_GPUTPCGMMergerResolve_step0 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerResolve_step1 - #define GPUCA_LB_GPUTPCGMMergerResolve_step1 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerResolve_step2 - #define GPUCA_LB_GPUTPCGMMergerResolve_step2 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerResolve_step3 - #define GPUCA_LB_GPUTPCGMMergerResolve_step3 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerResolve_step4 - #define GPUCA_LB_GPUTPCGMMergerResolve_step4 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerClearLinks - #define GPUCA_LB_GPUTPCGMMergerClearLinks 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerMergeWithinPrepare - #define GPUCA_LB_GPUTPCGMMergerMergeWithinPrepare 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerMergeSectorsPrepare - #define GPUCA_LB_GPUTPCGMMergerMergeSectorsPrepare 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerMergeBorders_step0 - #define GPUCA_LB_GPUTPCGMMergerMergeBorders_step0 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerMergeBorders_step2 - #define GPUCA_LB_GPUTPCGMMergerMergeBorders_step2 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerMergeCE - #define GPUCA_LB_GPUTPCGMMergerMergeCE 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerLinkExtrapolatedTracks - #define GPUCA_LB_GPUTPCGMMergerLinkExtrapolatedTracks 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerCollect - #define GPUCA_LB_GPUTPCGMMergerCollect 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerSortTracksPrepare - #define GPUCA_LB_GPUTPCGMMergerSortTracksPrepare 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerPrepareForFit_step0 - #define GPUCA_LB_GPUTPCGMMergerPrepareForFit_step0 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerPrepareForFit_step1 - #define GPUCA_LB_GPUTPCGMMergerPrepareForFit_step1 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerPrepareForFit_step2 - #define GPUCA_LB_GPUTPCGMMergerPrepareForFit_step2 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerFinalize_step0 - #define GPUCA_LB_GPUTPCGMMergerFinalize_step0 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerFinalize_step1 - #define GPUCA_LB_GPUTPCGMMergerFinalize_step1 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerFinalize_step2 - #define GPUCA_LB_GPUTPCGMMergerFinalize_step2 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerMergeLoopers_step0 - #define GPUCA_LB_GPUTPCGMMergerMergeLoopers_step0 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerMergeLoopers_step1 - #define GPUCA_LB_GPUTPCGMMergerMergeLoopers_step1 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMMergerMergeLoopers_step2 - #define GPUCA_LB_GPUTPCGMMergerMergeLoopers_step2 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMO2Output_prepare - #define GPUCA_LB_GPUTPCGMO2Output_prepare 256 - #endif - #ifndef GPUCA_LB_GPUTPCGMO2Output_output - #define GPUCA_LB_GPUTPCGMO2Output_output 256 - #endif - #ifndef GPUCA_LB_GPUTPCStartHitsFinder - #define GPUCA_LB_GPUTPCStartHitsFinder 256 - #endif - #ifndef GPUCA_LB_GPUTPCStartHitsSorter - #define GPUCA_LB_GPUTPCStartHitsSorter 256 - #endif - #ifndef GPUCA_LB_GPUTPCCFCheckPadBaseline - #define GPUCA_LB_GPUTPCCFCheckPadBaseline 576 - #endif - #ifndef GPUCA_LB_GPUTPCCFChargeMapFiller_fillIndexMap - #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillIndexMap 512 - #endif - #ifndef GPUCA_LB_GPUTPCCFChargeMapFiller_fillFromDigits - #define GPUCA_LB_GPUTPCCFChargeMapFiller_fillFromDigits 512 - #endif - #ifndef GPUCA_LB_GPUTPCCFChargeMapFiller_findFragmentStart - #define GPUCA_LB_GPUTPCCFChargeMapFiller_findFragmentStart 512 - #endif - #ifndef GPUCA_LB_GPUTPCCFPeakFinder - #define GPUCA_LB_GPUTPCCFPeakFinder 512 - #endif - #ifndef GPUCA_LB_GPUTPCCFNoiseSuppression - #define GPUCA_LB_GPUTPCCFNoiseSuppression 512 - #endif - #ifndef GPUCA_LB_GPUTPCCFDeconvolution - #define GPUCA_LB_GPUTPCCFDeconvolution 512 - #endif - #ifndef GPUCA_LB_GPUTPCCFClusterizer - #define GPUCA_LB_GPUTPCCFClusterizer 512 - #endif - #ifndef GPUCA_LB_GPUTPCNNClusterizerKernels - #define GPUCA_LB_GPUTPCNNClusterizerKernels 512 - #endif - #ifndef GPUCA_LB_GPUTrackingRefitKernel_mode0asGPU - #define GPUCA_LB_GPUTrackingRefitKernel_mode0asGPU 256 - #endif - #ifndef GPUCA_LB_GPUTrackingRefitKernel_mode1asTrackParCov - #define GPUCA_LB_GPUTrackingRefitKernel_mode1asTrackParCov 256 - #endif - #ifndef GPUCA_LB_GPUMemClean16 - #define GPUCA_LB_GPUMemClean16 GPUCA_THREAD_COUNT_DEFAULT, 1 - #endif - #ifndef GPUCA_LB_GPUitoa - #define GPUCA_LB_GPUitoa GPUCA_THREAD_COUNT_DEFAULT, 1 - #endif - // These kernel launch-bounds are derrived from one of the constants set above - #define GPUCA_LB_GPUTPCCFNoiseSuppression_noiseSuppression GPUCA_LB_GPUTPCCFNoiseSuppression - #define GPUCA_LB_GPUTPCCFNoiseSuppression_updatePeaks GPUCA_LB_GPUTPCCFNoiseSuppression - - #define GPUCA_LB_GPUTPCNNClusterizerKernels_runCfClusterizer GPUCA_LB_GPUTPCNNClusterizerKernels - #define GPUCA_LB_GPUTPCNNClusterizerKernels_fillInputNNCPU GPUCA_LB_GPUTPCNNClusterizerKernels - #define GPUCA_LB_GPUTPCNNClusterizerKernels_fillInputNNGPU 1024 - #define GPUCA_LB_GPUTPCNNClusterizerKernels_determineClass1Labels GPUCA_LB_GPUTPCNNClusterizerKernels - #define GPUCA_LB_GPUTPCNNClusterizerKernels_determineClass2Labels GPUCA_LB_GPUTPCNNClusterizerKernels - #define GPUCA_LB_GPUTPCNNClusterizerKernels_publishClass1Regression GPUCA_LB_GPUTPCNNClusterizerKernels - #define GPUCA_LB_GPUTPCNNClusterizerKernels_publishClass2Regression GPUCA_LB_GPUTPCNNClusterizerKernels - #define GPUCA_LB_GPUTPCNNClusterizerKernels_publishDeconvolutionFlags GPUCA_LB_GPUTPCNNClusterizerKernels - - #define GPUCA_LB_GPUTPCCFStreamCompaction_scanStart GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE - #define GPUCA_LB_GPUTPCCFStreamCompaction_scanUp GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE - #define GPUCA_LB_GPUTPCCFStreamCompaction_scanTop GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE - #define GPUCA_LB_GPUTPCCFStreamCompaction_scanDown GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE - #define GPUCA_LB_GPUTPCCFStreamCompaction_compactDigits GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE - #define GPUCA_LB_GPUTPCCompressionGatherKernels_unbuffered GPUCA_LB_COMPRESSION_GATHER - #define GPUCA_LB_GPUTPCCompressionGatherKernels_buffered32 GPUCA_LB_COMPRESSION_GATHER - #define GPUCA_LB_GPUTPCCompressionGatherKernels_buffered64 GPUCA_LB_COMPRESSION_GATHER - #define GPUCA_LB_GPUTPCCompressionGatherKernels_buffered128 GPUCA_LB_COMPRESSION_GATHER - #define GPUCA_LB_GPUTPCCompressionGatherKernels_multiBlock GPUCA_LB_COMPRESSION_GATHER - - // Defaults for non-LB parameters - #ifndef GPUCA_PAR_SORT_STARTHITS - #define GPUCA_PAR_SORT_STARTHITS 1 - #endif - #ifndef GPUCA_PAR_NEIGHBOURS_FINDER_MAX_NNEIGHUP - #define GPUCA_PAR_NEIGHBOURS_FINDER_MAX_NNEIGHUP 6 - #endif - #ifndef GPUCA_PAR_NEIGHBOURS_FINDER_UNROLL_GLOBAL - #define GPUCA_PAR_NEIGHBOURS_FINDER_UNROLL_GLOBAL 4 - #endif - #ifndef GPUCA_PAR_NEIGHBOURS_FINDER_UNROLL_SHARED - #define GPUCA_PAR_NEIGHBOURS_FINDER_UNROLL_SHARED 1 - #endif - #ifndef GPUCA_PAR_TRACKLET_SELECTOR_HITS_REG_SIZE - #define GPUCA_PAR_TRACKLET_SELECTOR_HITS_REG_SIZE 12 - #endif - #ifndef GPUCA_PAR_ALTERNATE_BORDER_SORT - #define GPUCA_PAR_ALTERNATE_BORDER_SORT 0 - #endif - #ifndef GPUCA_PAR_SORT_BEFORE_FIT - #define GPUCA_PAR_SORT_BEFORE_FIT 0 - #endif - #ifndef GPUCA_PAR_COMP_GATHER_KERNEL - #define GPUCA_PAR_COMP_GATHER_KERNEL 0 - #endif - #ifndef GPUCA_PAR_COMP_GATHER_MODE - #define GPUCA_PAR_COMP_GATHER_MODE 2 - #endif - #ifndef GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE - #define GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE 512 - #endif -#endif // defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_NO_LAUNCH_BOUNDS) - -#ifndef GPUCA_GPUCODE_GENRTC - // Defaults (also for CPU) for non-LB parameters - #ifndef GPUCA_PAR_SORT_STARTHITS - #define GPUCA_PAR_SORT_STARTHITS 0 - #endif - #ifndef GPUCA_PAR_NEIGHBOURS_FINDER_MAX_NNEIGHUP - #define GPUCA_PAR_NEIGHBOURS_FINDER_MAX_NNEIGHUP 0 - #endif - #ifndef GPUCA_PAR_NEIGHBOURS_FINDER_UNROLL_GLOBAL - #define GPUCA_PAR_NEIGHBOURS_FINDER_UNROLL_GLOBAL 0 - #endif - #ifndef GPUCA_PAR_NEIGHBOURS_FINDER_UNROLL_SHARED - #define GPUCA_PAR_NEIGHBOURS_FINDER_UNROLL_SHARED 0 - #endif - #ifndef GPUCA_PAR_TRACKLET_SELECTOR_HITS_REG_SIZE - #define GPUCA_PAR_TRACKLET_SELECTOR_HITS_REG_SIZE 0 - #endif - #ifndef GPUCA_PAR_ALTERNATE_BORDER_SORT - #define GPUCA_PAR_ALTERNATE_BORDER_SORT 0 - #endif - #ifndef GPUCA_PAR_SORT_BEFORE_FIT - #define GPUCA_PAR_SORT_BEFORE_FIT 0 - #endif - #ifndef GPUCA_PAR_COMP_GATHER_KERNEL - #define GPUCA_PAR_COMP_GATHER_KERNEL 0 - #endif - #ifndef GPUCA_PAR_COMP_GATHER_MODE - #define GPUCA_PAR_COMP_GATHER_MODE 0 - #endif - #ifndef GPUCA_PAR_NO_ATOMIC_PRECHECK - #define GPUCA_PAR_NO_ATOMIC_PRECHECK 0 - #endif - #ifndef GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE - #define GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE 0 - #endif - #ifndef GPUCA_PAR_DEDX_STORAGE_TYPE - #define GPUCA_PAR_DEDX_STORAGE_TYPE float - #endif - #ifndef GPUCA_PAR_MERGER_INTERPOLATION_ERROR_TYPE - #define GPUCA_PAR_MERGER_INTERPOLATION_ERROR_TYPE float - #endif -#endif // GPUCA_GPUCODE_GENRTC - -// clang-format on -#endif // GPUDEFPARAMETERSDEFAULTS_H diff --git a/GPU/GPUTracking/Definitions/GPUParameters.json b/GPU/GPUTracking/Definitions/GPUParameters.json new file mode 100644 index 0000000000000..e8f1c24520813 --- /dev/null +++ b/GPU/GPUTracking/Definitions/GPUParameters.json @@ -0,0 +1,582 @@ +{ + "CORE": { + "WARP_SIZE": { + "default": 32, + "MI100": 64, + "VEGA": 64, + "AMPERE": 32, + "TURING": 32 + }, + "THREAD_COUNT_DEFAULT": { + "default": 256, + "MI100": 256, + "VEGA": 256, + "AMPERE": 512, + "TURING": 512 + } + }, + "LB": { + "GPUTPCCreateTrackingData": { + "default": 256, + "MI100": [256, 7], + "VEGA": [192, 2], + "AMPERE": 384, + "TURING": 256 + }, + "GPUTPCTrackletConstructor": { + "default": 256, + "MI100": [768, 8], + "VEGA": [512, 10], + "AMPERE": [256, 2], + "TURING": [256, 2] + }, + "GPUTPCTrackletSelector": { + "default": 256, + "MI100": [384, 5], + "VEGA": [192, 10], + "AMPERE": [192, 3], + "TURING": [192, 3] + }, + "GPUTPCNeighboursFinder": { + "default": 256, + "MI100": [192, 8], + "VEGA": [960, 8], + "AMPERE": [640, 1], + "TURING": [640, 1] + }, + "GPUTPCNeighboursCleaner": { + "default": 256, + "MI100": [128, 5], + "VEGA": [384, 9], + "AMPERE": 512, + "TURING": 512 + }, + "GPUTPCExtrapolationTracking": { + "default": 256, + "MI100": [256, 7], + "VEGA": [256, 2], + "AMPERE": [128, 4], + "TURING": [192, 2] + }, + "GPUTRDTrackerKernels_gpuVersion": { + "default": 512 + }, + "GPUTPCCreateOccupancyMap_fill": { + "default": 256 + }, + "GPUTPCCreateOccupancyMap_fold": { + "default": 256 + }, + "GPUTRDTrackerKernels_o2Version": { + "default": 512 + }, + "GPUTPCCompressionKernels_step0attached": { + "default": 256, + "MI100": [128, 1], + "VEGA": [64, 2], + "AMPERE": [64, 2], + "TURING": 128 + }, + "GPUTPCCompressionKernels_step1unattached": { + "default": 256, + "MI100": [512, 2], + "VEGA": [512, 2], + "AMPERE": [512, 3], + "TURING": [512, 2] + }, + "GPUTPCDecompressionKernels_step0attached": { + "default": 256, + "MI100": [128, 2], + "VEGA": [128, 2], + "AMPERE": [32, 1], + "TURING": [32, 1] + }, + "GPUTPCDecompressionKernels_step1unattached": { + "default": 256, + "MI100": [64, 2], + "VEGA": [64, 2], + "AMPERE": [32, 1], + "TURING": [32, 1] + }, + "GPUTPCDecompressionUtilKernels_sortPerSectorRow": { + "default": 256 + }, + "GPUTPCDecompressionUtilKernels_countFilteredClusters": { + "default": 256 + }, + "GPUTPCDecompressionUtilKernels_storeFilteredClusters": { + "default": 256 + }, + "GPUTPCCFDecodeZS": { + "default": [128, 4], + "MI100": [64, 4], + "VEGA": [64, 1], + "AMPERE": [64, 10], + "TURING": [64, 8] + }, + "GPUTPCCFDecodeZSLink": { + "default": "GPUCA_WARP_SIZE", + "MI100": "GPUCA_WARP_SIZE", + "VEGA": "GPUCA_WARP_SIZE", + "AMPERE": "GPUCA_WARP_SIZE", + "TURING": "GPUCA_WARP_SIZE" + }, + "GPUTPCCFDecodeZSDenseLink": { + "default": "GPUCA_WARP_SIZE", + "MI100": ["GPUCA_WARP_SIZE", 4], + "VEGA": ["GPUCA_WARP_SIZE", 14], + "AMPERE": "GPUCA_WARP_SIZE", + "TURING": "GPUCA_WARP_SIZE" + }, + "GPUTPCCFGather": { + "default": [1024, 1], + "MI100": [1024, 5], + "VEGA": [1024, 1], + "AMPERE": [1024, 1], + "TURING": [1024, 1] + }, + "COMPRESSION_GATHER": { + "default": 1024, + "MI100": 1024, + "VEGA": 1024, + "AMPERE": 1024, + "TURING": 1024 + }, + "GPUTPCGMMergerTrackFit": { + "default": 256, + "MI100": [192, 2], + "VEGA": [64, 7], + "AMPERE": [64, 4], + "TURING": [32, 8] + }, + "GPUTPCGMMergerFollowLoopers": { + "default": 256, + "MI100": [256, 5], + "VEGA": [256, 4], + "AMPERE": [64, 12], + "TURING": [128, 4] + }, + "GPUTPCGMMergerSectorRefit": { + "default": 256, + "MI100": [64, 4], + "VEGA": [256, 2], + "AMPERE": [32, 6], + "TURING": [64, 5] + }, + "GPUTPCGMMergerUnpackResetIds": { + "default": 256, + "MI100": 256, + "VEGA": 256, + "AMPERE": 256, + "TURING": 256 + }, + "GPUTPCGMMergerUnpackGlobal": { + "default": 256, + "MI100": 256, + "VEGA": 256, + "AMPERE": 256, + "TURING": 256 + }, + "GPUTPCGMMergerResolve_step0": { + "default": 256, + "MI100": 512, + "VEGA": 256, + "AMPERE": 256, + "TURING": 256 + }, + "GPUTPCGMMergerResolve_step1": { + "default": 256, + "MI100": 512, + "VEGA": 256, + "AMPERE": 256, + "TURING": 256 + }, + "GPUTPCGMMergerResolve_step2": { + "default": 256, + "MI100": 512, + "VEGA": 256, + "AMPERE": 256, + "TURING": 256 + }, + "GPUTPCGMMergerResolve_step3": { + "default": 256, + "MI100": 512, + "VEGA": 256, + "AMPERE": 256, + "TURING": 256 + }, + "GPUTPCGMMergerResolve_step4": { + "default": 256, + "MI100": 512, + "VEGA": 256, + "AMPERE": [256, 4], + "TURING": [256, 4] + }, + "GPUTPCGMMergerClearLinks": { + "default": 256, + "MI100": 256, + "VEGA": 256, + "AMPERE": 256, + "TURING": 256 + }, + "GPUTPCGMMergerMergeWithinPrepare": { + "default": 256, + "MI100": 256, + "VEGA": 256, + "AMPERE": 256, + "TURING": 256 + }, + "GPUTPCGMMergerMergeSectorsPrepare": { + "default": 256, + "MI100": 256, + "VEGA": 256, + "AMPERE": [256, 2], + "TURING": [256, 2] + }, + "GPUTPCGMMergerMergeBorders_step0": { + "default": 256, + "MI100": 512, + "VEGA": 256, + "AMPERE": 192, + "TURING": 192 + }, + "GPUTPCGMMergerMergeBorders_step2": { + "default": 256, + "MI100": 512, + "VEGA": 256, + "AMPERE": [64, 2], + "TURING": 256 + }, + "GPUTPCGMMergerMergeCE": { + "default": 256, + "MI100": 512, + "VEGA": 256, + "AMPERE": 256, + "TURING": 256 + }, + "GPUTPCGMMergerLinkExtrapolatedTracks": { + "default": 256, + "MI100": 256, + "VEGA": 256, + "AMPERE": 256, + "TURING": 256 + }, + "GPUTPCGMMergerCollect": { + "default": 256, + "MI100": [768, 1], + "VEGA": [1024, 1], + "AMPERE": [256, 2], + "TURING": [128, 2] + }, + "GPUTPCGMMergerSortTracksPrepare": { + "default": 256, + "MI100": 256, + "VEGA": 256, + "AMPERE": 256, + "TURING": 256 + }, + "GPUTPCGMMergerPrepareForFit_step0": { + "default": 256, + "MI100": 256, + "VEGA": 256, + "AMPERE": 256, + "TURING": 256 + }, + "GPUTPCGMMergerPrepareForFit_step1": { + "default": 256, + "MI100": 256, + "VEGA": 256, + "AMPERE": 256, + "TURING": 256 + }, + "GPUTPCGMMergerPrepareForFit_step2": { + "default": 256, + "MI100": 256, + "VEGA": 256, + "AMPERE": 256, + "TURING": 256 + }, + "GPUTPCGMMergerFinalize_step0": { + "default": 256, + "VEGA": 256 + }, + "GPUTPCGMMergerFinalize_step1": { + "default": 256, + "VEGA": 256 + }, + "GPUTPCGMMergerFinalize_step2": { + "default": 256, + "VEGA": 256 + }, + "GPUTPCGMMergerMergeLoopers_step0": { + "default": 256 + }, + "GPUTPCGMMergerMergeLoopers_step1": { + "default": 256 + }, + "GPUTPCGMMergerMergeLoopers_step2": { + "default": 256 + }, + "GPUTPCGMO2Output_prepare": { + "default": 256 + }, + "GPUTPCGMO2Output_output": { + "default": 256 + }, + "GPUTPCStartHitsFinder": { + "default": 256, + "MI100": [1024, 2], + "VEGA": [1024, 7], + "AMPERE": 512, + "TURING": 512 + }, + "GPUTPCStartHitsSorter": { + "default": 256, + "MI100": [1024, 5], + "VEGA": [512, 7], + "AMPERE": [512, 1], + "TURING": [512, 1] + }, + "GPUTPCCFCheckPadBaseline": { + "default": 64, + "MI100": [64, 10], + "VEGA": [64, 2], + "AMPERE": [64, 8] + }, + "GPUTPCCFChargeMapFiller_fillIndexMap": { + "default": 512, + "MI100": 512, + "VEGA": 512, + "AMPERE": 448 + }, + "GPUTPCCFChargeMapFiller_fillFromDigits": { + "default": 512, + "MI100": 512, + "VEGA": 512, + "AMPERE": 448 + }, + "GPUTPCCFChargeMapFiller_findFragmentStart": { + "default": 512, + "MI100": 512, + "VEGA": 512, + "AMPERE": 448 + }, + "GPUTPCCFPeakFinder": { + "default": 512, + "MI100": [512, 9], + "VEGA": [512, 4], + "AMPERE": 128 + }, + "GPUTPCCFNoiseSuppression": { + "default": 512, + "MI100": 512, + "VEGA": 512, + "AMPERE": 448 + }, + "GPUTPCCFDeconvolution": { + "default": 512, + "MI100": [512, 5], + "VEGA": [512, 5], + "AMPERE": 384 + }, + "GPUTPCCFClusterizer": { + "default": 512, + "MI100": [448, 3], + "VEGA": [512, 2], + "AMPERE": 448 + }, + "GPUTPCNNClusterizerKernels": { + "default": 512 + }, + "GPUTrackingRefitKernel_mode0asGPU": { + "default": 256 + }, + "GPUTrackingRefitKernel_mode1asTrackParCov": { + "default": 256 + }, + "GPUMemClean16": { + "default": ["GPUCA_THREAD_COUNT_DEFAULT", 1] + }, + "GPUitoa": { + "default": ["GPUCA_THREAD_COUNT_DEFAULT", 1] + }, + "GPUTPCCFNoiseSuppression_noiseSuppression": { + "default": "GPUCA_LB_GPUTPCCFNoiseSuppression" + }, + "GPUTPCCFNoiseSuppression_updatePeaks": { + "default": "GPUCA_LB_GPUTPCCFNoiseSuppression" + }, + "GPUTPCNNClusterizerKernels_runCfClusterizer": { + "default": "GPUCA_LB_GPUTPCNNClusterizerKernels" + }, + "GPUTPCNNClusterizerKernels_fillInputNNCPU": { + "default": "GPUCA_LB_GPUTPCNNClusterizerKernels" + }, + "GPUTPCNNClusterizerKernels_fillInputNNGPU": { + "default": 1024 + }, + "GPUTPCNNClusterizerKernels_determineClass1Labels": { + "default": "GPUCA_LB_GPUTPCNNClusterizerKernels" + }, + "GPUTPCNNClusterizerKernels_determineClass2Labels": { + "default": "GPUCA_LB_GPUTPCNNClusterizerKernels" + }, + "GPUTPCNNClusterizerKernels_publishClass1Regression": { + "default": "GPUCA_LB_GPUTPCNNClusterizerKernels" + }, + "GPUTPCNNClusterizerKernels_publishClass2Regression": { + "default": "GPUCA_LB_GPUTPCNNClusterizerKernels" + }, + "GPUTPCNNClusterizerKernels_publishDeconvolutionFlags": { + "default": "GPUCA_LB_GPUTPCNNClusterizerKernels" + }, + "GPUTPCCFStreamCompaction_scanStart": { + "default": "GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE" + }, + "GPUTPCCFStreamCompaction_scanUp": { + "default": "GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE" + }, + "GPUTPCCFStreamCompaction_scanTop": { + "default": "GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE" + }, + "GPUTPCCFStreamCompaction_scanDown": { + "default": "GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE" + }, + "GPUTPCCFStreamCompaction_compactDigits": { + "default": "GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE" + }, + "GPUTPCCompressionGatherKernels_unbuffered": { + "default": "GPUCA_LB_COMPRESSION_GATHER" + }, + "GPUTPCCompressionGatherKernels_buffered32": { + "default": "GPUCA_LB_COMPRESSION_GATHER" + }, + "GPUTPCCompressionGatherKernels_buffered64": { + "default": "GPUCA_LB_COMPRESSION_GATHER" + }, + "GPUTPCCompressionGatherKernels_buffered128": { + "default": "GPUCA_LB_COMPRESSION_GATHER" + }, + "GPUTPCCompressionGatherKernels_multiBlock": { + "default": "GPUCA_LB_COMPRESSION_GATHER" + }, + "GPUTPCGMMergerFinalize_0": { + "default": 256, + "MI100": 256, + "AMPERE": 256, + "TURING": 256 + }, + "GPUTPCGMMergerFinalize_1": { + "default": 256, + "MI100": 256, + "AMPERE": 256, + "TURING": 256 + }, + "GPUTPCGMMergerFinalize_2": { + "default": 256, + "MI100": 256, + "AMPERE": 256, + "TURING": 256 + } + }, + "PAR": { + "AMD_EUS_PER_CU": { + "default": 0, + "default_cpu": 0, + "MI100": 4, + "VEGA": 4 + }, + "SORT_STARTHITS": { + "default": 1, + "default_cpu": 0 + }, + "NEIGHBOURS_FINDER_MAX_NNEIGHUP": { + "default": 6, + "default_cpu": 0, + "MI100": 10, + "VEGA": 4, + "AMPERE": 4, + "TURING": 4 + }, + "NEIGHBOURS_FINDER_UNROLL_GLOBAL": { + "default": 4, + "default_cpu": 0, + "MI100": 4, + "VEGA": 2 + }, + "NEIGHBOURS_FINDER_UNROLL_SHARED": { + "default": 1, + "default_cpu": 0, + "MI100": 0, + "VEGA": 0 + }, + "TRACKLET_SELECTOR_HITS_REG_SIZE": { + "default": 12, + "default_cpu": 0, + "MI100": 9, + "VEGA": 27, + "AMPERE": 20, + "TURING": 20 + }, + "ALTERNATE_BORDER_SORT": { + "default": 0, + "default_cpu": 0, + "MI100": 1, + "VEGA": 1, + "AMPERE": 1, + "TURING": 1 + }, + "SORT_BEFORE_FIT": { + "default": 0, + "default_cpu": 0, + "MI100": 1, + "VEGA": 1, + "AMPERE": 1, + "TURING": 1 + }, + "NO_ATOMIC_PRECHECK": { + "default": 0, + "default_cpu": 0, + "MI100": 1, + "VEGA": 1, + "AMPERE": 1, + "TURING": 1 + }, + "DEDX_STORAGE_TYPE": { + "default": "float", + "default_cpu": "float", + "MI100": "uint16_t", + "VEGA": "uint16_t", + "AMPERE": "uint16_t", + "TURING": "uint16_t" + }, + "MERGER_INTERPOLATION_ERROR_TYPE": { + "default": "float", + "default_cpu": "float", + "MI100": "half", + "VEGA": "half", + "AMPERE": "half", + "TURING": "half" + }, + "COMP_GATHER_KERNEL": { + "default": 0, + "default_cpu": 0, + "MI100": 4, + "VEGA": 4, + "AMPERE": 4, + "TURING": 4 + }, + "COMP_GATHER_MODE": { + "default": 2, + "default_cpu": 0, + "MI100": 3, + "VEGA": 3, + "AMPERE": 3, + "TURING": 3 + }, + "CF_SCAN_WORKGROUP_SIZE": { + "default": 512, + "default_cpu": 0 + } + } +} diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index 9bfe6feb14d8d..c61056466929e 100644 --- a/GPU/GPUTracking/Definitions/GPUSettingsList.h +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -624,7 +624,7 @@ AddSubConfig(GPUSettingsEG, EG) EndConfig() #endif // BeginConfig -//Settings for the O2 workfllow +//Settings for the O2 workflow #if !defined(QCONFIG_PARSER_CXX) && (defined(GPUCA_O2_LIB) || defined(GPUCA_O2_INTERFACE)) BeginSubConfig(GPUSettingsO2, global, configStandalone, "O2", 0, "O2 workflow settings", global) AddOption(solenoidBzNominalGPU, float, -1e6f, "", 0, "Field strength of solenoid Bz in kGaus") diff --git a/GPU/GPUTracking/cmake/generateGPUParamHeader.cmake b/GPU/GPUTracking/cmake/generateGPUParamHeader.cmake new file mode 100644 index 0000000000000..712bf4641b825 --- /dev/null +++ b/GPU/GPUTracking/cmake/generateGPUParamHeader.cmake @@ -0,0 +1,37 @@ +# 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 generateGPUParamHeader.cmake +# author Gabriele Cimador + +function(generate_gpu_param_header GPU_ARCH OUT_HEADER) + set(GPU_PARAM_JSON ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Definitions/GPUParameters.json) + set(TARGET_ARCH "UNKNOWN") + if(GPU_ARCH STREQUAL "AUTO") + detect_gpu_arch("AUTO") + else() + set(TARGET_ARCH ${GPU_ARCH}) + endif() + add_custom_command( + OUTPUT ${OUT_HEADER} + COMMAND ${CMAKE_COMMAND} + -DOUT_HEADER=${OUT_HEADER} + -DGPU_PARAM_JSON=${GPU_PARAM_JSON} + -DTARGET_ARCH_SHORT=${TARGET_ARCH} + -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/gpu_param_header_generator.cmake + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/gpu_param_header_generator.cmake + ${GPU_PARAM_JSON} + COMMENT "Generating GPU parameter header for ${TARGET_ARCH}" + VERBATIM + ) + add_custom_target(GPU_PARAM_HEADER_${GPU_ARCH}_ALL ALL DEPENDS ${OUT_HEADER}) +endfunction() \ No newline at end of file diff --git a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake new file mode 100644 index 0000000000000..3949322b5abfa --- /dev/null +++ b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake @@ -0,0 +1,105 @@ +# 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 gpu_param_header_generator.cmake +# author Gabriele Cimador + +file(READ "${GPU_PARAM_JSON}" JSON_CONTENT) +set(TMP_HEADER "${OUT_HEADER}.tmp") +file(WRITE "${TMP_HEADER}" "#ifndef GPUDEFPARAMETERSDEFAULTS_H\n#define GPUDEFPARAMETERSDEFAULTS_H\n\n") +file(APPEND "${TMP_HEADER}" "// This file is auto-generated from gpu_params.json. Do not edit directly.\n") +string(REPLACE "," ";" ARCH_LIST "${TARGET_ARCH_SHORT}") +file(APPEND "${TMP_HEADER}" "// Architectures: ${TARGET_ARCH_SHORT}\n\n") +file(APPEND "${TMP_HEADER}" "#if defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_NO_LAUNCH_BOUNDS) // Avoid including for RTC generation besides normal include protection.\n\n") + +# Types +set(TYPES CORE LB PAR) +foreach(ARCH IN LISTS ARCH_LIST) + file(APPEND "${TMP_HEADER}" "#if defined(GPUCA_GPUTYPE_${ARCH})\n\n") + foreach(TYPE IN LISTS TYPES) + # Get all keys of this TYPE as a semicolon-separated list + string(JSON n_params LENGTH "${JSON_CONTENT}" "${TYPE}") + math(EXPR last "${n_params} - 1") + foreach(i RANGE 0 ${last}) + string(JSON param_name MEMBER "${JSON_CONTENT}" "${TYPE}" "${i}") + string(JSON n_archs LENGTH "${JSON_CONTENT}" "${TYPE}" "${param_name}") + math(EXPR last_arch "${n_archs} - 1") + + foreach(iArch RANGE 0 ${last_arch}) + string(JSON arch MEMBER "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${iArch}") + if(arch STREQUAL "${ARCH}") + string(JSON param_values GET "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${ARCH}") + if(TYPE STREQUAL "LB") + set(MACRO_NAME "GPUCA_LB_${param_name}") + elseif(TYPE STREQUAL "PAR") + set(MACRO_NAME "GPUCA_PAR_${param_name}") + else() + set(MACRO_NAME "GPUCA_${param_name}") + endif() + set(vals "${param_values}") + string(REGEX REPLACE "^\\[ *" "" vals "${vals}") + string(REGEX REPLACE " *\\]$" "" vals "${vals}") + string(REGEX REPLACE "\"" "" vals "${vals}") + set(MACRO_DEFINITION "#define ${MACRO_NAME} ${vals}") + file(APPEND "${TMP_HEADER}" "${MACRO_DEFINITION}\n") + endif() + endforeach() + endforeach() + endforeach() + file(APPEND "${TMP_HEADER}" "\n#endif // GPUCA_GPUTYPE_${ARCH}\n\n") +endforeach() + +file(APPEND "${TMP_HEADER}" "\n// Default parameters if not defined for the target architecture\n\n") +#Default parameters +foreach(TYPE IN LISTS TYPES) + # Get all keys of this TYPE as a semicolon-separated list + string(JSON n_params LENGTH "${JSON_CONTENT}" "${TYPE}") + math(EXPR last "${n_params} - 1") + foreach(i RANGE 0 ${last}) + string(JSON param_name MEMBER "${JSON_CONTENT}" "${TYPE}" "${i}") + string(JSON param_values GET "${JSON_CONTENT}" "${TYPE}" "${param_name}" "default") + if(TYPE STREQUAL "LB") + set(MACRO_NAME "GPUCA_LB_${param_name}") + elseif(TYPE STREQUAL "PAR") + set(MACRO_NAME "GPUCA_PAR_${param_name}") + else() + set(MACRO_NAME "GPUCA_${param_name}") + endif() + set(vals "${param_values}") + string(REGEX REPLACE "^\\[ *" "" vals "${vals}") + string(REGEX REPLACE " *\\]$" "" vals "${vals}") + string(REGEX REPLACE "\"" "" vals "${vals}") + set(MACRO_DEFINITION "#define ${MACRO_NAME} ${vals}") + file(APPEND "${TMP_HEADER}" "#ifndef ${MACRO_NAME}\n ${MACRO_DEFINITION}\n#endif\n\n") + endforeach() +endforeach() +file(APPEND "${TMP_HEADER}" "#endif // defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_NO_LAUNCH_BOUNDS)\n\n") + +#Defaults for non-LB parameters also for CPU fallback +file(APPEND "${TMP_HEADER}" "#ifndef GPUCA_GPUCODE_GENRTC //Defaults for non-LB parameters also for CPU fallback\n\n") # Get all keys of this TYPE as a semicolon-separated list +string(JSON n_params LENGTH "${JSON_CONTENT}" "PAR") +math(EXPR last "${n_params} - 1") +foreach(i RANGE 0 ${last}) + string(JSON param_name MEMBER "${JSON_CONTENT}" "PAR" "${i}") + string(JSON param_values GET "${JSON_CONTENT}" "PAR" "${param_name}" "default_cpu") + set(MACRO_NAME "GPUCA_PAR_${param_name}") + set(vals "${param_values}") + string(REGEX REPLACE "^\\[ *" "" vals "${vals}") + string(REGEX REPLACE " *\\]$" "" vals "${vals}") + string(REGEX REPLACE "\"" "" vals "${vals}") + set(MACRO_DEFINITION "#define ${MACRO_NAME} ${vals}") + file(APPEND "${TMP_HEADER}" "#ifndef ${MACRO_NAME}\n ${MACRO_DEFINITION}\n#endif\n\n") +endforeach() +file(APPEND "${TMP_HEADER}" "\n#endif // GPUCA_GPUCODE_GENRTC\n") + +file(APPEND "${TMP_HEADER}" "\n#endif // GPUDEFPARAMETERSDEFAULTS_H\n") +file(RENAME "${TMP_HEADER}" "${OUT_HEADER}") +message(STATUS "Generated ${OUT_HEADER}") diff --git a/GPU/documentation/build-O2.md b/GPU/documentation/build-O2.md index dd21f7e154a63..b04fe562b8c2f 100644 --- a/GPU/documentation/build-O2.md +++ b/GPU/documentation/build-O2.md @@ -37,7 +37,7 @@ Advantages: - One can see enabled GPU features / versions / architectures in the version string of `gpu-system`. Disadvantages: -- Need system `CMake` >= `3.26` for the detsction at aliBuild level. +- Need system `CMake` >= `3.26` for the detection at aliBuild level. - `FindO2GPU.cmake` is duplicated in O2 and alidist and must be kept in sync. But at least this is checked and gives an error otherwise. - Running cmake during the system check takes around 5 sec for every aliBuild command involving O2 or ONNX. diff --git a/dependencies/FindO2GPU.cmake b/dependencies/FindO2GPU.cmake index 21e2d7cad239a..3cfcaef82fcca 100644 --- a/dependencies/FindO2GPU.cmake +++ b/dependencies/FindO2GPU.cmake @@ -10,7 +10,7 @@ # or submit itself to any jurisdiction. # NOTE!!!! - Whenever this file is changed, move it over to alidist/resources -# FindO2GPU.cmake Version 9 +# FindO2GPU.cmake Version 10 set(CUDA_COMPUTETARGET_DEFAULT_FULL 80-real 86-real 89-real 120-real 75-virtual) set(HIP_AMDGPUTARGET_DEFAULT_FULL gfx906;gfx908) @@ -44,34 +44,53 @@ if(HIP_AMDGPUTARGET AND HIP_AMDGPUTARGET STREQUAL "default") set(HIP_AMDGPUTARGET ${HIP_AMDGPUTARGET_DEFAULT_FULL}) endif() -function(set_target_cuda_arch target) - if(CUDA_COMPUTETARGET AND (CUDA_COMPUTETARGET MATCHES "86" OR CUDA_COMPUTETARGET MATCHES "89")) +function(detect_gpu_arch backend) # Detect GPU architecture, optionally filterring by backend + set(TARGET_ARCH "") + set(CUDA_TARGET "") + set(HIP_TARGET "") + + if(CUDA_COMPUTETARGET AND CUDA_COMPUTETARGET MATCHES "86|89") + set(CUDA_TARGET AMPERE) message(STATUS "Using optimized CUDA settings for Ampere GPU") - target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_AMPERE) elseif(CUDA_COMPUTETARGET AND CUDA_COMPUTETARGET MATCHES "75") + set(CUDA_TARGET TURING) message(STATUS "Using optimized CUDA settings for Turing GPU") - target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_TURING) else() + set(CUDA_TARGET AMPERE) message(STATUS "Defaulting optimized CUDA settings for Ampere GPU") - target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_AMPERE) endif() -endfunction() -function(set_target_hip_arch target) if(HIP_AMDGPUTARGET AND HIP_AMDGPUTARGET MATCHES "gfx906") + set(HIP_TARGET VEGA) message(STATUS "Using optimized HIP settings for MI50 GPU") - target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_VEGA) elseif(HIP_AMDGPUTARGET AND HIP_AMDGPUTARGET MATCHES "gfx908") + set(HIP_TARGET MI100) message(STATUS "Using optimized HIP settings for MI100 GPU") - target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_MI100) elseif(HIP_AMDGPUTARGET AND HIP_AMDGPUTARGET MATCHES "gfx90a") + set(HIP_TARGET MI100) message(STATUS "Using optimized HIP settings for MI210 GPU") - target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_MI100) else() - target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_VEGA) + set(HIP_TARGET VEGA) + message(STATUS "Defaulting optimized HIP settings for VEGA GPU") + endif() + + if(backend STREQUAL "CUDA") # CUDA filter + set(TARGET_ARCH "${CUDA_TARGET}" PARENT_SCOPE) + return() + elseif(backend STREQUAL "HIP") # HIP filter + set(TARGET_ARCH "${HIP_TARGET}" PARENT_SCOPE) + return() + else() # Return both + set(TARGET_ARCH "${CUDA_TARGET},${HIP_TARGET}" PARENT_SCOPE) endif() endfunction() +function(set_target_gpu_arch backend target) + detect_gpu_arch("${backend}") + message(STATUS "Compiling for ${TARGET_ARCH}") + target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_${TARGET_ARCH}) +endfunction() + # Need to strip c++17 imposed by alidist defaults STRING(REGEX REPLACE "\-std=[^ ]*" "" O2_GPU_CMAKE_CXX_FLAGS_NOSTD "${CMAKE_CXX_FLAGS}") diff --git a/log.txt b/log.txt new file mode 100644 index 0000000000000..e69de29bb2d1d From f683cac8423902087d678de4181d4a2089376296 Mon Sep 17 00:00:00 2001 From: Gabriele Cimador Date: Wed, 28 Jan 2026 17:53:20 +0100 Subject: [PATCH 146/234] GPU Framework: refactor generation of default GPU parameters --- GPU/GPUTracking/CMakeLists.txt | 2 +- .../Definitions/Parameters/.clang-format | 1 + .../{ => Parameters}/.clang-format-ignore | 0 .../{ => Parameters}/GPUParameters.json | 0 .../cmake/generateGPUParamHeader.cmake | 37 ------ .../cmake/gpu_param_header_generator.cmake | 117 ++++++++---------- dependencies/FindO2GPU.cmake | 8 +- 7 files changed, 58 insertions(+), 107 deletions(-) create mode 100644 GPU/GPUTracking/Definitions/Parameters/.clang-format rename GPU/GPUTracking/Definitions/{ => Parameters}/.clang-format-ignore (100%) rename GPU/GPUTracking/Definitions/{ => Parameters}/GPUParameters.json (100%) delete mode 100644 GPU/GPUTracking/cmake/generateGPUParamHeader.cmake diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index a2d91b6ed4c5e..816d578fb31a3 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -109,7 +109,7 @@ set(SRCS_NO_H SectorTracker/GPUTPCTrackerDump.cxx set(ON_THE_FLY_DIR ${CMAKE_CURRENT_BINARY_DIR}/include_gpu_onthefly) file(MAKE_DIRECTORY ${ON_THE_FLY_DIR}) -include(cmake/generateGPUParamHeader.cmake) +include(cmake/gpu_param_header_generator.cmake) set(GPU_DEFAULT_PARAMS_HEADER ${ON_THE_FLY_DIR}/GPUDefParametersDefaults.h) generate_gpu_param_header("AUTO" ${GPU_DEFAULT_PARAMS_HEADER}) # generate header with default GPU parameters, arch selected by CMake variables diff --git a/GPU/GPUTracking/Definitions/Parameters/.clang-format b/GPU/GPUTracking/Definitions/Parameters/.clang-format new file mode 100644 index 0000000000000..e3845288a2aec --- /dev/null +++ b/GPU/GPUTracking/Definitions/Parameters/.clang-format @@ -0,0 +1 @@ +DisableFormat: true diff --git a/GPU/GPUTracking/Definitions/.clang-format-ignore b/GPU/GPUTracking/Definitions/Parameters/.clang-format-ignore similarity index 100% rename from GPU/GPUTracking/Definitions/.clang-format-ignore rename to GPU/GPUTracking/Definitions/Parameters/.clang-format-ignore diff --git a/GPU/GPUTracking/Definitions/GPUParameters.json b/GPU/GPUTracking/Definitions/Parameters/GPUParameters.json similarity index 100% rename from GPU/GPUTracking/Definitions/GPUParameters.json rename to GPU/GPUTracking/Definitions/Parameters/GPUParameters.json diff --git a/GPU/GPUTracking/cmake/generateGPUParamHeader.cmake b/GPU/GPUTracking/cmake/generateGPUParamHeader.cmake deleted file mode 100644 index 712bf4641b825..0000000000000 --- a/GPU/GPUTracking/cmake/generateGPUParamHeader.cmake +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2019-2020 CERN and copyright holders of ALICE O2. -# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -# All rights not expressly granted are reserved. -# -# This software is distributed under the terms of the GNU General Public -# License v3 (GPL Version 3), copied verbatim in the file "COPYING". -# -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization -# or submit itself to any jurisdiction. - -# file generateGPUParamHeader.cmake -# author Gabriele Cimador - -function(generate_gpu_param_header GPU_ARCH OUT_HEADER) - set(GPU_PARAM_JSON ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Definitions/GPUParameters.json) - set(TARGET_ARCH "UNKNOWN") - if(GPU_ARCH STREQUAL "AUTO") - detect_gpu_arch("AUTO") - else() - set(TARGET_ARCH ${GPU_ARCH}) - endif() - add_custom_command( - OUTPUT ${OUT_HEADER} - COMMAND ${CMAKE_COMMAND} - -DOUT_HEADER=${OUT_HEADER} - -DGPU_PARAM_JSON=${GPU_PARAM_JSON} - -DTARGET_ARCH_SHORT=${TARGET_ARCH} - -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/gpu_param_header_generator.cmake - DEPENDS - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/gpu_param_header_generator.cmake - ${GPU_PARAM_JSON} - COMMENT "Generating GPU parameter header for ${TARGET_ARCH}" - VERBATIM - ) - add_custom_target(GPU_PARAM_HEADER_${GPU_ARCH}_ALL ALL DEPENDS ${OUT_HEADER}) -endfunction() \ No newline at end of file diff --git a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake index 3949322b5abfa..38b92421616f2 100644 --- a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake +++ b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake @@ -12,31 +12,18 @@ # file gpu_param_header_generator.cmake # author Gabriele Cimador -file(READ "${GPU_PARAM_JSON}" JSON_CONTENT) -set(TMP_HEADER "${OUT_HEADER}.tmp") -file(WRITE "${TMP_HEADER}" "#ifndef GPUDEFPARAMETERSDEFAULTS_H\n#define GPUDEFPARAMETERSDEFAULTS_H\n\n") -file(APPEND "${TMP_HEADER}" "// This file is auto-generated from gpu_params.json. Do not edit directly.\n") -string(REPLACE "," ";" ARCH_LIST "${TARGET_ARCH_SHORT}") -file(APPEND "${TMP_HEADER}" "// Architectures: ${TARGET_ARCH_SHORT}\n\n") -file(APPEND "${TMP_HEADER}" "#if defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_NO_LAUNCH_BOUNDS) // Avoid including for RTC generation besides normal include protection.\n\n") - -# Types -set(TYPES CORE LB PAR) -foreach(ARCH IN LISTS ARCH_LIST) - file(APPEND "${TMP_HEADER}" "#if defined(GPUCA_GPUTYPE_${ARCH})\n\n") - foreach(TYPE IN LISTS TYPES) - # Get all keys of this TYPE as a semicolon-separated list - string(JSON n_params LENGTH "${JSON_CONTENT}" "${TYPE}") +function(generate_macros json_content header types arch_key use_ifndef_guard) + foreach(TYPE IN LISTS types) + string(JSON n_params LENGTH "${json_content}" "${TYPE}") math(EXPR last "${n_params} - 1") foreach(i RANGE 0 ${last}) - string(JSON param_name MEMBER "${JSON_CONTENT}" "${TYPE}" "${i}") + string(JSON param_name MEMBER "${json_content}" "${TYPE}" "${i}") string(JSON n_archs LENGTH "${JSON_CONTENT}" "${TYPE}" "${param_name}") math(EXPR last_arch "${n_archs} - 1") - foreach(iArch RANGE 0 ${last_arch}) string(JSON arch MEMBER "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${iArch}") - if(arch STREQUAL "${ARCH}") - string(JSON param_values GET "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${ARCH}") + if(arch STREQUAL "${arch_key}") + string(JSON param_values GET "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${arch_key}") if(TYPE STREQUAL "LB") set(MACRO_NAME "GPUCA_LB_${param_name}") elseif(TYPE STREQUAL "PAR") @@ -49,57 +36,57 @@ foreach(ARCH IN LISTS ARCH_LIST) string(REGEX REPLACE " *\\]$" "" vals "${vals}") string(REGEX REPLACE "\"" "" vals "${vals}") set(MACRO_DEFINITION "#define ${MACRO_NAME} ${vals}") - file(APPEND "${TMP_HEADER}" "${MACRO_DEFINITION}\n") + if(use_ifndef_guard) + # fallback defaults are wrapped in #ifndef + file(APPEND "${header}" "#ifndef ${MACRO_NAME}\n ${MACRO_DEFINITION}\n#endif\n\n") + else() + file(APPEND "${header}" "${MACRO_DEFINITION}\n") + endif() endif() endforeach() endforeach() endforeach() - file(APPEND "${TMP_HEADER}" "\n#endif // GPUCA_GPUTYPE_${ARCH}\n\n") -endforeach() +endfunction() + +function(generate_gpu_param_header GPU_ARCH OUT_HEADER) + set(GPU_PARAM_JSON ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Definitions/Parameters/GPUParameters.json) + set(TARGET_ARCH "UNKNOWN") + if(GPU_ARCH STREQUAL "AUTO") + detect_gpu_arch("ALL") + else() + set(TARGET_ARCH ${GPU_ARCH}) + endif() + file(READ "${GPU_PARAM_JSON}" JSON_CONTENT) + set(TMP_HEADER "${OUT_HEADER}.tmp") + message(STATUS "OUT_HEADER = '${OUT_HEADER}'") + message(STATUS "TMP_HEADER = '${TMP_HEADER}'") + file(WRITE "${TMP_HEADER}" "#ifndef GPUDEFPARAMETERSDEFAULTS_H\n#define GPUDEFPARAMETERSDEFAULTS_H\n\n") + file(APPEND "${TMP_HEADER}" "// This file is auto-generated from gpu_params.json. Do not edit directly.\n") + string(REPLACE "," ";" ARCH_LIST "${TARGET_ARCH}") + file(APPEND "${TMP_HEADER}" "// Architectures: ${TARGET_ARCH}\n\n") + file(APPEND "${TMP_HEADER}" "#if defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_NO_LAUNCH_BOUNDS) // Avoid including for RTC generation besides normal include protection.\n\n") -file(APPEND "${TMP_HEADER}" "\n// Default parameters if not defined for the target architecture\n\n") -#Default parameters -foreach(TYPE IN LISTS TYPES) - # Get all keys of this TYPE as a semicolon-separated list - string(JSON n_params LENGTH "${JSON_CONTENT}" "${TYPE}") - math(EXPR last "${n_params} - 1") - foreach(i RANGE 0 ${last}) - string(JSON param_name MEMBER "${JSON_CONTENT}" "${TYPE}" "${i}") - string(JSON param_values GET "${JSON_CONTENT}" "${TYPE}" "${param_name}" "default") - if(TYPE STREQUAL "LB") - set(MACRO_NAME "GPUCA_LB_${param_name}") - elseif(TYPE STREQUAL "PAR") - set(MACRO_NAME "GPUCA_PAR_${param_name}") - else() - set(MACRO_NAME "GPUCA_${param_name}") - endif() - set(vals "${param_values}") - string(REGEX REPLACE "^\\[ *" "" vals "${vals}") - string(REGEX REPLACE " *\\]$" "" vals "${vals}") - string(REGEX REPLACE "\"" "" vals "${vals}") - set(MACRO_DEFINITION "#define ${MACRO_NAME} ${vals}") - file(APPEND "${TMP_HEADER}" "#ifndef ${MACRO_NAME}\n ${MACRO_DEFINITION}\n#endif\n\n") + # Types + set(TYPES CORE LB PAR) + # Per architecture definitions + foreach(ARCH IN LISTS ARCH_LIST) + file(APPEND "${TMP_HEADER}" "#if defined(GPUCA_GPUTYPE_${ARCH})\n\n") + generate_macros("${JSON_CONTENT}" "${TMP_HEADER}" "${TYPES}" "${ARCH}" "") + file(APPEND "${TMP_HEADER}" "\n#endif // GPUCA_GPUTYPE_${ARCH}\n\n") endforeach() -endforeach() -file(APPEND "${TMP_HEADER}" "#endif // defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_NO_LAUNCH_BOUNDS)\n\n") -#Defaults for non-LB parameters also for CPU fallback -file(APPEND "${TMP_HEADER}" "#ifndef GPUCA_GPUCODE_GENRTC //Defaults for non-LB parameters also for CPU fallback\n\n") # Get all keys of this TYPE as a semicolon-separated list -string(JSON n_params LENGTH "${JSON_CONTENT}" "PAR") -math(EXPR last "${n_params} - 1") -foreach(i RANGE 0 ${last}) - string(JSON param_name MEMBER "${JSON_CONTENT}" "PAR" "${i}") - string(JSON param_values GET "${JSON_CONTENT}" "PAR" "${param_name}" "default_cpu") - set(MACRO_NAME "GPUCA_PAR_${param_name}") - set(vals "${param_values}") - string(REGEX REPLACE "^\\[ *" "" vals "${vals}") - string(REGEX REPLACE " *\\]$" "" vals "${vals}") - string(REGEX REPLACE "\"" "" vals "${vals}") - set(MACRO_DEFINITION "#define ${MACRO_NAME} ${vals}") - file(APPEND "${TMP_HEADER}" "#ifndef ${MACRO_NAME}\n ${MACRO_DEFINITION}\n#endif\n\n") -endforeach() -file(APPEND "${TMP_HEADER}" "\n#endif // GPUCA_GPUCODE_GENRTC\n") + # Default parameters + file(APPEND "${TMP_HEADER}" "\n// Default parameters if not defined for the target architecture\n\n") + generate_macros("${JSON_CONTENT}" "${TMP_HEADER}" "${TYPES}" "default" "use_ifndef_guard") + file(APPEND "${TMP_HEADER}" "#endif // defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_NO_LAUNCH_BOUNDS)\n\n") + + # CPU fallback + file(APPEND "${TMP_HEADER}" "#ifndef GPUCA_GPUCODE_GENRTC //Defaults for non-LB parameters also for CPU fallback\n\n") # Get all keys of this TYPE as a semicolon-separated list + generate_macros("${JSON_CONTENT}" "${TMP_HEADER}" "PAR" "default_cpu" "use_ifndef_guard") + file(APPEND "${TMP_HEADER}" "\n#endif // GPUCA_GPUCODE_GENRTC\n") -file(APPEND "${TMP_HEADER}" "\n#endif // GPUDEFPARAMETERSDEFAULTS_H\n") -file(RENAME "${TMP_HEADER}" "${OUT_HEADER}") -message(STATUS "Generated ${OUT_HEADER}") + file(APPEND "${TMP_HEADER}" "\n#endif // GPUDEFPARAMETERSDEFAULTS_H\n") + file(RENAME "${TMP_HEADER}" "${OUT_HEADER}") + message(STATUS "Generated ${OUT_HEADER}") + add_custom_target(GPU_PARAM_HEADER_${GPU_ARCH}_ALL ALL DEPENDS ${OUT_HEADER} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/gpu_param_header_generator.cmake ${GPU_PARAM_JSON}) +endfunction() \ No newline at end of file diff --git a/dependencies/FindO2GPU.cmake b/dependencies/FindO2GPU.cmake index 3cfcaef82fcca..4ed29ec61f3e1 100644 --- a/dependencies/FindO2GPU.cmake +++ b/dependencies/FindO2GPU.cmake @@ -45,9 +45,6 @@ if(HIP_AMDGPUTARGET AND HIP_AMDGPUTARGET STREQUAL "default") endif() function(detect_gpu_arch backend) # Detect GPU architecture, optionally filterring by backend - set(TARGET_ARCH "") - set(CUDA_TARGET "") - set(HIP_TARGET "") if(CUDA_COMPUTETARGET AND CUDA_COMPUTETARGET MATCHES "86|89") set(CUDA_TARGET AMPERE) @@ -80,8 +77,11 @@ function(detect_gpu_arch backend) # Detect GPU architecture, optionally filterri elseif(backend STREQUAL "HIP") # HIP filter set(TARGET_ARCH "${HIP_TARGET}" PARENT_SCOPE) return() - else() # Return both + elseif(backend STREQUAL "ALL") # Return both set(TARGET_ARCH "${CUDA_TARGET},${HIP_TARGET}" PARENT_SCOPE) + return() + else() + message(FATAL_ERROR "Unknown backend provided: ${backend}") endif() endfunction() From fe431a1ae55bf5a05e617210f7fab1f4f35aa378 Mon Sep 17 00:00:00 2001 From: Gabriele Cimador Date: Thu, 29 Jan 2026 13:16:58 +0100 Subject: [PATCH 147/234] GPU Framework: Add OpenCL support to GPU param header generation + update CFCheckPadBaseline parameters --- .../Definitions/Parameters/GPUParameters.json | 8 ++++---- .../cmake/gpu_param_header_generator.cmake | 20 ++++++++++++------- dependencies/FindO2GPU.cmake | 19 ++++++++++++------ 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/GPU/GPUTracking/Definitions/Parameters/GPUParameters.json b/GPU/GPUTracking/Definitions/Parameters/GPUParameters.json index e8f1c24520813..674efc9ea0912 100644 --- a/GPU/GPUTracking/Definitions/Parameters/GPUParameters.json +++ b/GPU/GPUTracking/Definitions/Parameters/GPUParameters.json @@ -338,10 +338,10 @@ "TURING": [512, 1] }, "GPUTPCCFCheckPadBaseline": { - "default": 64, - "MI100": [64, 10], - "VEGA": [64, 2], - "AMPERE": [64, 8] + "default": 576, + "MI100": [576, 2], + "VEGA": [576, 2], + "AMPERE": [576, 2] }, "GPUTPCCFChargeMapFiller_fillIndexMap": { "default": 512, diff --git a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake index 38b92421616f2..3770e30f2583c 100644 --- a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake +++ b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake @@ -49,7 +49,7 @@ function(generate_macros json_content header types arch_key use_ifndef_guard) endfunction() function(generate_gpu_param_header GPU_ARCH OUT_HEADER) - set(GPU_PARAM_JSON ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Definitions/Parameters/GPUParameters.json) + set(GPU_PARAM_JSON ${CMAKE_CURRENT_SOURCE_DIR}/Definitions/Parameters/GPUParameters.json) set(TARGET_ARCH "UNKNOWN") if(GPU_ARCH STREQUAL "AUTO") detect_gpu_arch("ALL") @@ -58,8 +58,6 @@ function(generate_gpu_param_header GPU_ARCH OUT_HEADER) endif() file(READ "${GPU_PARAM_JSON}" JSON_CONTENT) set(TMP_HEADER "${OUT_HEADER}.tmp") - message(STATUS "OUT_HEADER = '${OUT_HEADER}'") - message(STATUS "TMP_HEADER = '${TMP_HEADER}'") file(WRITE "${TMP_HEADER}" "#ifndef GPUDEFPARAMETERSDEFAULTS_H\n#define GPUDEFPARAMETERSDEFAULTS_H\n\n") file(APPEND "${TMP_HEADER}" "// This file is auto-generated from gpu_params.json. Do not edit directly.\n") string(REPLACE "," ";" ARCH_LIST "${TARGET_ARCH}") @@ -69,11 +67,19 @@ function(generate_gpu_param_header GPU_ARCH OUT_HEADER) # Types set(TYPES CORE LB PAR) # Per architecture definitions + set(_first TRUE) foreach(ARCH IN LISTS ARCH_LIST) - file(APPEND "${TMP_HEADER}" "#if defined(GPUCA_GPUTYPE_${ARCH})\n\n") - generate_macros("${JSON_CONTENT}" "${TMP_HEADER}" "${TYPES}" "${ARCH}" "") - file(APPEND "${TMP_HEADER}" "\n#endif // GPUCA_GPUTYPE_${ARCH}\n\n") + if(_first) + file(APPEND "${TMP_HEADER}" "#if defined(GPUCA_GPUTYPE_${ARCH})\n\n") + set(_first FALSE) + else() + file(APPEND "${TMP_HEADER}" "#elif defined(GPUCA_GPUTYPE_${ARCH})\n\n") + endif() + generate_macros("${JSON_CONTENT}" "${TMP_HEADER}" "${TYPES}" "${ARCH}" "") endforeach() + if(NOT _first) + file(APPEND "${TMP_HEADER}" "#else\n#error GPU TYPE NOT SET\n#endif\n") + endif() # Default parameters file(APPEND "${TMP_HEADER}" "\n// Default parameters if not defined for the target architecture\n\n") @@ -81,7 +87,7 @@ function(generate_gpu_param_header GPU_ARCH OUT_HEADER) file(APPEND "${TMP_HEADER}" "#endif // defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_NO_LAUNCH_BOUNDS)\n\n") # CPU fallback - file(APPEND "${TMP_HEADER}" "#ifndef GPUCA_GPUCODE_GENRTC //Defaults for non-LB parameters also for CPU fallback\n\n") # Get all keys of this TYPE as a semicolon-separated list + file(APPEND "${TMP_HEADER}" "#ifndef GPUCA_GPUCODE_GENRTC //Defaults for non-LB parameters also for CPU fallback\n\n") generate_macros("${JSON_CONTENT}" "${TMP_HEADER}" "PAR" "default_cpu" "use_ifndef_guard") file(APPEND "${TMP_HEADER}" "\n#endif // GPUCA_GPUCODE_GENRTC\n") diff --git a/dependencies/FindO2GPU.cmake b/dependencies/FindO2GPU.cmake index 4ed29ec61f3e1..e02bf932ab784 100644 --- a/dependencies/FindO2GPU.cmake +++ b/dependencies/FindO2GPU.cmake @@ -73,13 +73,21 @@ function(detect_gpu_arch backend) # Detect GPU architecture, optionally filterri if(backend STREQUAL "CUDA") # CUDA filter set(TARGET_ARCH "${CUDA_TARGET}" PARENT_SCOPE) - return() elseif(backend STREQUAL "HIP") # HIP filter set(TARGET_ARCH "${HIP_TARGET}" PARENT_SCOPE) - return() - elseif(backend STREQUAL "ALL") # Return both - set(TARGET_ARCH "${CUDA_TARGET},${HIP_TARGET}" PARENT_SCOPE) - return() + elseif(backend STREQUAL "ALL") # Return enabled backends + set(_archs "") + if(CUDA_ENABLED) + list(APPEND _archs "${CUDA_TARGET}") + endif() + if(HIP_ENABLED) + list(APPEND _archs "${HIP_TARGET}") + endif() + if(OPENCL_ENABLED) + list(APPEND _archs "OPENCL") + endif() + list(JOIN _archs "," TARGET_ARCH) + set(TARGET_ARCH "${TARGET_ARCH}" PARENT_SCOPE) else() message(FATAL_ERROR "Unknown backend provided: ${backend}") endif() @@ -87,7 +95,6 @@ endfunction() function(set_target_gpu_arch backend target) detect_gpu_arch("${backend}") - message(STATUS "Compiling for ${TARGET_ARCH}") target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_${TARGET_ARCH}) endfunction() From 5a15ab5c1b12b1010a439bcd16751e375059795f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ku=C4=8Dera?= <26327373+vkucera@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:47:27 +0100 Subject: [PATCH 148/234] GPU: Delete unused files (#15015) * GPU: Remove unused files * Add missing suffix * Revert "Add missing suffix" This reverts commit 81879979abeac8839164d57d33d65a392c4b3aea. * Remove cxx suffix --- ...tGPUsortHIP.hip.cxx => testGPUsortHIP.hip} | 0 .../SectorTracker/GPUTPCDefinitions.h | 25 -- .../utils/makefile_opencl_compiler.cxx | 258 ------------------ .../utils/opencl_compiler_structs.h | 28 -- GPU/GPUTracking/utils/opencl_obtain_program.h | 91 ------ 5 files changed, 402 deletions(-) rename GPU/GPUTracking/Base/hip/test/{testGPUsortHIP.hip.cxx => testGPUsortHIP.hip} (100%) delete mode 100644 GPU/GPUTracking/SectorTracker/GPUTPCDefinitions.h delete mode 100644 GPU/GPUTracking/utils/makefile_opencl_compiler.cxx delete mode 100644 GPU/GPUTracking/utils/opencl_compiler_structs.h delete mode 100644 GPU/GPUTracking/utils/opencl_obtain_program.h diff --git a/GPU/GPUTracking/Base/hip/test/testGPUsortHIP.hip.cxx b/GPU/GPUTracking/Base/hip/test/testGPUsortHIP.hip similarity index 100% rename from GPU/GPUTracking/Base/hip/test/testGPUsortHIP.hip.cxx rename to GPU/GPUTracking/Base/hip/test/testGPUsortHIP.hip diff --git a/GPU/GPUTracking/SectorTracker/GPUTPCDefinitions.h b/GPU/GPUTracking/SectorTracker/GPUTPCDefinitions.h deleted file mode 100644 index 7d9d607b9b88d..0000000000000 --- a/GPU/GPUTracking/SectorTracker/GPUTPCDefinitions.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUTPCDefinitions.h -/// \author Sergey Gorbunov, David Rohr - -#ifndef GPUTPCDEFINITIONS_H -#define GPUTPCDEFINITIONS_H - -#include "AliHLTDataTypes.h" - -namespace GPUTPCDefinitions -{ -extern const AliHLTComponentDataType fgkTrackletsDataType; -} - -#endif // GPUTPCDEFINITIONS_H diff --git a/GPU/GPUTracking/utils/makefile_opencl_compiler.cxx b/GPU/GPUTracking/utils/makefile_opencl_compiler.cxx deleted file mode 100644 index f6400cc3369e0..0000000000000 --- a/GPU/GPUTracking/utils/makefile_opencl_compiler.cxx +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file makefile_opencl_compiler.cxx -/// \author David Rohr - -#define CL_TARGET_OPENCL_VERSION 220 -#define _CRT_SECURE_NO_WARNINGS -#include "CL/opencl.h" -#include -#include -#include -#include -#include - -#include "opencl_compiler_structs.h" - -#define quit(arg) \ - { \ - fprintf(stderr, arg "\n"); \ - return (1); \ - } -#define DEFAULT_OPENCL_COMPILER_OPTIONS "" -#define DEFAULT_OUTPUT_FILE "opencl.out" - -int32_t main(int argc, char** argv) -{ - const char* output_file = DEFAULT_OUTPUT_FILE; - std::string compiler_options = DEFAULT_OPENCL_COMPILER_OPTIONS; - std::vector files; - - printf("Passing command line options:\n"); - bool add_option = false; - for (int32_t i = 1; i < argc; i++) { - if (add_option) { - compiler_options += " "; - compiler_options += argv[i]; - } else if (strcmp(argv[i], "--") == 0) { - add_option = true; - } else if (strcmp(argv[i], "-output-file") == 0) { - if (++i >= argc) { - quit("Output file name missing"); - } - output_file = argv[i]; - } else { - fprintf(stderr, "%s\n", argv[i]); - files.push_back(argv[i]); - } - } - - cl_int ocl_error; - cl_uint num_platforms; - if (clGetPlatformIDs(0, nullptr, &num_platforms) != CL_SUCCESS) { - quit("Error getting OpenCL Platform Count"); - } - if (num_platforms == 0) { - quit("No OpenCL Platform found"); - } - printf("%d OpenCL Platforms found\n", num_platforms); - - // Query platforms - cl_platform_id* platforms = new cl_platform_id[num_platforms]; - if (platforms == nullptr) { - quit("Memory allocation error"); - } - if (clGetPlatformIDs(num_platforms, platforms, nullptr) != CL_SUCCESS) { - quit("Error getting OpenCL Platforms"); - } - - cl_platform_id platform; - bool found = false; - - _makefiles_opencl_platform_info pinfo; - for (uint32_t i_platform = 0; i_platform < num_platforms; i_platform++) { - clGetPlatformInfo(platforms[i_platform], CL_PLATFORM_PROFILE, 64, pinfo.platform_profile, nullptr); - clGetPlatformInfo(platforms[i_platform], CL_PLATFORM_VERSION, 64, pinfo.platform_version, nullptr); - clGetPlatformInfo(platforms[i_platform], CL_PLATFORM_NAME, 64, pinfo.platform_name, nullptr); - clGetPlatformInfo(platforms[i_platform], CL_PLATFORM_VENDOR, 64, pinfo.platform_vendor, nullptr); - printf("Available Platform %u: (%s %s) %s %s\n", i_platform, pinfo.platform_profile, pinfo.platform_version, pinfo.platform_vendor, pinfo.platform_name); - if (strcmp(pinfo.platform_vendor, "Advanced Micro Devices, Inc.") == 0 && strcmp(pinfo.platform_version, "OpenCL 2.0 AMD-APP (1800.8)") == 0) { - found = true; - printf("AMD OpenCL Platform found (%u)\n", i_platform); - platform = platforms[i_platform]; - break; - } - } - if (found == false) { - quit("Did not find AMD OpenCL Platform"); - } - - if (clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 0, nullptr, &pinfo.count) != CL_SUCCESS) { - quit("Error getting OPENCL Device Count"); - } - - // Query devices - cl_device_id* devices = new cl_device_id[pinfo.count]; - if (devices == nullptr) { - quit("Memory allocation error"); - } - if (clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, pinfo.count, devices, nullptr) != CL_SUCCESS) { - quit("Error getting OpenCL devices"); - } - - _makefiles_opencl_device_info dinfo; - cl_device_type device_type; - cl_uint freq, shaders; - - printf("Available OPENCL devices:\n"); - for (uint32_t i = 0; i < pinfo.count; i++) { - printf("Examining device %u\n", i); - - clGetDeviceInfo(devices[i], CL_DEVICE_NAME, 64, dinfo.device_name, nullptr); - clGetDeviceInfo(devices[i], CL_DEVICE_VENDOR, 64, dinfo.device_vendor, nullptr); - clGetDeviceInfo(devices[i], CL_DEVICE_TYPE, sizeof(cl_device_type), &device_type, nullptr); - clGetDeviceInfo(devices[i], CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(freq), &freq, nullptr); - clGetDeviceInfo(devices[i], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(shaders), &shaders, nullptr); - clGetDeviceInfo(devices[i], CL_DEVICE_ADDRESS_BITS, sizeof(dinfo.nbits), &dinfo.nbits, nullptr); - printf("Found Device %u : %s %s (Frequency %d, Shaders %d, %d bit)\n", i, dinfo.device_vendor, dinfo.device_name, (int32_t)freq, (int32_t)shaders, (int32_t)dinfo.nbits); - } - - if (files.size() == 0) { - quit("Syntax: opencl [-output-file OUTPUT_FILE] FILE1 [FILE2] ... [FILEn] [-- COMPILER_OPTION_1] [COMPILER_OPTION_2] ... [COMPILER_OPTION_N]"); - } - - char** buffers = (char**)malloc(files.size() * sizeof(char*)); - if (buffers == nullptr) { - quit("Memory allocation error\n"); - } - for (uint32_t i = 0; i < files.size(); i++) { - printf("Reading source file %s\n", files[i]); - FILE* fp = fopen(files[i], "rb"); - if (fp == nullptr) { - printf("Cannot open %s\n", files[i]); - free(buffers); - return (1); - } - fseek(fp, 0, SEEK_END); - size_t file_size = ftell(fp); - fseek(fp, 0, SEEK_SET); - - buffers[i] = (char*)malloc(file_size + 1); - if (buffers[i] == nullptr) { - quit("Memory allocation error"); - } - if (fread(buffers[i], 1, file_size, fp) != file_size) { - quit("Error reading file"); - } - buffers[i][file_size] = 0; - fclose(fp); - } - - printf("Creating OpenCL Context\n"); - // Create OpenCL context - cl_context context = clCreateContext(nullptr, pinfo.count, devices, nullptr, nullptr, &ocl_error); - if (ocl_error != CL_SUCCESS) { - quit("Error creating OpenCL context"); - } - - printf("Creating OpenCL Program Object\n"); - // Create OpenCL program object - cl_program program = clCreateProgramWithSource(context, (cl_uint)files.size(), (const char**)buffers, nullptr, &ocl_error); - if (ocl_error != CL_SUCCESS) { - quit("Error creating program object"); - } - - printf("Compiling OpenCL Program\n"); - // Compile program - ocl_error = clBuildProgram(program, pinfo.count, devices, compiler_options.c_str(), nullptr, nullptr); - if (ocl_error != CL_SUCCESS) { - fprintf(stderr, "OpenCL Error while building program: %d (Compiler options: %s)\n", ocl_error, compiler_options.c_str()); - fprintf(stderr, "OpenCL Kernel:\n\n"); - for (uint32_t i = 0; i < files.size(); i++) { - printf("%s\n\n", buffers[i]); - } - - for (uint32_t i = 0; i < pinfo.count; i++) { - cl_build_status status; - clGetProgramBuildInfo(program, devices[i], CL_PROGRAM_BUILD_STATUS, sizeof(status), &status, nullptr); - if (status == CL_BUILD_ERROR) { - size_t log_size; - clGetProgramBuildInfo(program, devices[i], CL_PROGRAM_BUILD_LOG, 0, nullptr, &log_size); - char* build_log = (char*)malloc(log_size + 1); - if (build_log == nullptr) { - quit("Memory allocation error"); - } - clGetProgramBuildInfo(program, devices[i], CL_PROGRAM_BUILD_LOG, log_size, build_log, nullptr); - fprintf(stderr, "Build Log (device %d):\n\n%s\n\n", i, build_log); - free(build_log); - } - } - } - for (uint32_t i = 0; i < files.size(); i++) { - free(buffers[i]); - } - free(buffers); - if (ocl_error != CL_SUCCESS) { - return (1); - } - - printf("Obtaining program binaries\n"); - size_t* binary_sizes = (size_t*)malloc(pinfo.count * sizeof(size_t)); - if (binary_sizes == nullptr) { - quit("Memory allocation error"); - } - clGetProgramInfo(program, CL_PROGRAM_BINARY_SIZES, pinfo.count * sizeof(size_t), binary_sizes, nullptr); - char** binary_buffers = (char**)malloc(pinfo.count * sizeof(char*)); - if (binary_buffers == nullptr) { - quit("Memory allocation error"); - } - for (uint32_t i = 0; i < pinfo.count; i++) { - printf("Binary size for device %d: %d\n", i, (int32_t)binary_sizes[i]); - binary_buffers[i] = (char*)malloc(binary_sizes[i]); - memset(binary_buffers[i], 0, binary_sizes[i]); - if (binary_buffers[i] == nullptr) { - quit("Memory allocation error"); - } - } - clGetProgramInfo(program, CL_PROGRAM_BINARIES, pinfo.count * sizeof(char*), binary_buffers, nullptr); - - printf("Programs obtained successfully, cleaning up opencl\n"); - clReleaseProgram(program); - clReleaseContext(context); - - printf("Writing binaries to file (%s)\n", output_file); - FILE* fp; - fp = fopen(output_file, "w+b"); - if (fp == nullptr) { - quit("Error opening output file\n"); - } - const char* magic_bytes = "QOCLPB"; - fwrite(magic_bytes, 1, strlen(magic_bytes) + 1, fp); - fwrite(&pinfo, 1, sizeof(pinfo), fp); - for (uint32_t i = 0; i < pinfo.count; i++) { - clGetDeviceInfo(devices[i], CL_DEVICE_NAME, 64, dinfo.device_name, nullptr); - clGetDeviceInfo(devices[i], CL_DEVICE_VENDOR, 64, dinfo.device_vendor, nullptr); - dinfo.binary_size = binary_sizes[i]; - fwrite(&dinfo, 1, sizeof(dinfo), fp); - fwrite(binary_buffers[i], 1, binary_sizes[i], fp); - } - fclose(fp); - - printf("All done, cleaning up remaining buffers\n"); - for (uint32_t i = 0; i < pinfo.count; i++) { - free(binary_buffers[i]); - } - free(binary_sizes); - free(binary_buffers); - - return (0); -} diff --git a/GPU/GPUTracking/utils/opencl_compiler_structs.h b/GPU/GPUTracking/utils/opencl_compiler_structs.h deleted file mode 100644 index 68e0a4f184480..0000000000000 --- a/GPU/GPUTracking/utils/opencl_compiler_structs.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file opencl_compiler_structs.h -/// \author David Rohr - -struct _makefiles_opencl_platform_info { - char platform_profile[64]; - char platform_version[64]; - char platform_name[64]; - char platform_vendor[64]; - cl_uint count; -}; - -struct _makefiles_opencl_device_info { - char device_name[64]; - char device_vendor[64]; - cl_uint nbits; - size_t binary_size; -}; diff --git a/GPU/GPUTracking/utils/opencl_obtain_program.h b/GPU/GPUTracking/utils/opencl_obtain_program.h deleted file mode 100644 index 6c10ca9d47de1..0000000000000 --- a/GPU/GPUTracking/utils/opencl_obtain_program.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file opencl_obtain_program.h -/// \author David Rohr - -#ifndef MAKEFILES_OPENCL_OBTAIN_PROGRAMH -#define MAKEFILES_OPENCL_OBTAIN_PROGRAMH - -#include -#include -#include "opencl_compiler_structs.h" - -static int32_t _makefiles_opencl_obtain_program_helper(cl_context context, cl_uint num_devices, cl_device_id* devices, cl_program* program, char* binaries) -{ - const char* magic_bytes = "QOCLPB"; - if (strncmp(magic_bytes, binaries, strlen(magic_bytes)) != 0) { - printf("Internal error accessing opencl program\n"); - return (1); - } - char* current_ptr = binaries + strlen(magic_bytes) + 1; - _makefiles_opencl_platform_info* pinfo = (_makefiles_opencl_platform_info*)current_ptr; - current_ptr += sizeof(_makefiles_opencl_platform_info); - - if (num_devices != pinfo->count) { - printf("Number of devices differs from number of devices in opencl program\n"); - return (1); - } - // printf("Obtaining program for OpenCL Platform: (%s %s) %s %s\n", pinfo->platform_profile, pinfo->platform_version, pinfo->platform_vendor, pinfo->platform_name); - - std::vector program_sizes(pinfo->count); - std::vector program_binaries(pinfo->count); - - for (uint32_t i = 0; i < pinfo->count; i++) { - char device_name[64], device_vendor[64]; - cl_uint nbits; - clGetDeviceInfo(devices[i], CL_DEVICE_NAME, 64, device_name, nullptr); - clGetDeviceInfo(devices[i], CL_DEVICE_VENDOR, 64, device_vendor, nullptr); - clGetDeviceInfo(devices[i], CL_DEVICE_ADDRESS_BITS, sizeof(nbits), &nbits, nullptr); - _makefiles_opencl_device_info* dinfo = (_makefiles_opencl_device_info*)current_ptr; - if (strcmp(device_name, dinfo->device_name) != 0 || strcmp(device_vendor, dinfo->device_vendor) != 0) { - printf("Device list is different to device list from opencl program (Device %d: '%s - %s' != '%s - %s')\n", i, device_vendor, device_name, dinfo->device_vendor, dinfo->device_name); - return (1); - } - if (nbits != dinfo->nbits) { - printf("Pointer size of device and stored device binary differs\n"); - return (1); - } - current_ptr += sizeof(_makefiles_opencl_device_info); - // printf("Device %d: %s %s (size %ld)\n", i, dinfo->device_vendor, dinfo->device_name, (int64_t) dinfo->binary_size); - program_sizes[i] = dinfo->binary_size; - program_binaries[i] = current_ptr; - current_ptr += dinfo->binary_size; - } - - cl_int return_status[pinfo->count]; - cl_int ocl_error; - *program = clCreateProgramWithBinary(context, num_devices, devices, program_sizes.data(), (const uint8_t**)program_binaries.data(), return_status, &ocl_error); - - if (ocl_error != CL_SUCCESS) { - printf("Error loading program\n"); - return (1); - } - - for (uint32_t i = 0; i < pinfo->count; i++) { - if (return_status[i] != CL_SUCCESS) { - printf("Error loading program for device %d\n", i); - clReleaseProgram(*program); - return (1); - } - } - - ocl_error = clBuildProgram(*program, num_devices, devices, "", nullptr, nullptr); - if (ocl_error != CL_SUCCESS) { - printf("Error building program\n"); - clReleaseProgram(*program); - return (1); - } - - return (0); -} - -#endif From d64bc8603cc75d8de8e6523d75ac49f83f265364 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 5 Feb 2026 12:07:23 +0100 Subject: [PATCH 149/234] Add the .clang-format-ignore (#15019) --- .clang-format-ignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .clang-format-ignore diff --git a/.clang-format-ignore b/.clang-format-ignore new file mode 100644 index 0000000000000..a6c57f5fb2ffb --- /dev/null +++ b/.clang-format-ignore @@ -0,0 +1 @@ +*.json From 414ba09ac65b6bfe4202cab6327246817dee2646 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 5 Feb 2026 10:24:37 +0100 Subject: [PATCH 150/234] Add back tuned parameters for old architectures TAHITI TESLA FERMI PASCAL KEPLER --- .../Definitions/Parameters/.clang-format | 1 - .../Parameters/.clang-format-ignore | 1 - .../Definitions/Parameters/GPUParameters.json | 46 +++++++++++++++++-- 3 files changed, 41 insertions(+), 7 deletions(-) delete mode 100644 GPU/GPUTracking/Definitions/Parameters/.clang-format delete mode 100644 GPU/GPUTracking/Definitions/Parameters/.clang-format-ignore diff --git a/GPU/GPUTracking/Definitions/Parameters/.clang-format b/GPU/GPUTracking/Definitions/Parameters/.clang-format deleted file mode 100644 index e3845288a2aec..0000000000000 --- a/GPU/GPUTracking/Definitions/Parameters/.clang-format +++ /dev/null @@ -1 +0,0 @@ -DisableFormat: true diff --git a/GPU/GPUTracking/Definitions/Parameters/.clang-format-ignore b/GPU/GPUTracking/Definitions/Parameters/.clang-format-ignore deleted file mode 100644 index 5ffee2498bd7e..0000000000000 --- a/GPU/GPUTracking/Definitions/Parameters/.clang-format-ignore +++ /dev/null @@ -1 +0,0 @@ -GPUParameters.json diff --git a/GPU/GPUTracking/Definitions/Parameters/GPUParameters.json b/GPU/GPUTracking/Definitions/Parameters/GPUParameters.json index 674efc9ea0912..285919559c04c 100644 --- a/GPU/GPUTracking/Definitions/Parameters/GPUParameters.json +++ b/GPU/GPUTracking/Definitions/Parameters/GPUParameters.json @@ -1,11 +1,17 @@ { "CORE": { "WARP_SIZE": { - "default": 32, - "MI100": 64, - "VEGA": 64, - "AMPERE": 32, - "TURING": 32 + "default": 32, + "default_cpu": 1, + "MI100": 64, + "VEGA": 64, + "TAHITI": 32, + "TESLA": 32, + "FERMI": 32, + "PASCAL": 32, + "KEPLER": 32, + "AMPERE": 32, + "TURING": 32 }, "THREAD_COUNT_DEFAULT": { "default": 256, @@ -27,6 +33,11 @@ "default": 256, "MI100": [768, 8], "VEGA": [512, 10], + "TAHITI": [256, 2], + "TESLA": [256, 1], + "FERMI": [256, 2], + "PASCAL": [1024, 2], + "KEPLER": [512, 4], "AMPERE": [256, 2], "TURING": [256, 2] }, @@ -34,6 +45,11 @@ "default": 256, "MI100": [384, 5], "VEGA": [192, 10], + "TAHITI": [256, 3], + "TESLA": [256, 1], + "FERMI": [256, 3], + "PASCAL": [512, 4], + "KEPLER": [256, 3], "AMPERE": [192, 3], "TURING": [192, 3] }, @@ -41,6 +57,11 @@ "default": 256, "MI100": [192, 8], "VEGA": [960, 8], + "TAHITI": 256, + "TESLA": 256, + "FERMI": 256, + "PASCAL": 512, + "KEPLER": 256, "AMPERE": [640, 1], "TURING": [640, 1] }, @@ -48,6 +69,11 @@ "default": 256, "MI100": [128, 5], "VEGA": [384, 9], + "TAHITI": 256, + "TESLA": 256, + "FERMI": 256, + "PASCAL": 256, + "KEPLER": 256, "AMPERE": 512, "TURING": 512 }, @@ -327,6 +353,11 @@ "default": 256, "MI100": [1024, 2], "VEGA": [1024, 7], + "TAHITI": 256, + "TESLA": 256, + "PASCAL": 256, + "FERMI": 256, + "KEPLER": 256, "AMPERE": 512, "TURING": 512 }, @@ -334,6 +365,11 @@ "default": 256, "MI100": [1024, 5], "VEGA": [512, 7], + "TAHITI": 256, + "TESLA": 256, + "PASCAL": 256, + "FERMI": 256, + "KEPLER": 256, "AMPERE": [512, 1], "TURING": [512, 1] }, From 024cbcab8238cc0a7c4a6259d518fabbfc498b91 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 5 Feb 2026 10:29:50 +0100 Subject: [PATCH 151/234] Don't use 'No CUDA devices found' as CUDA architecture --- dependencies/FindO2GPU.cmake | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/dependencies/FindO2GPU.cmake b/dependencies/FindO2GPU.cmake index e02bf932ab784..ec6b7323ad5d1 100644 --- a/dependencies/FindO2GPU.cmake +++ b/dependencies/FindO2GPU.cmake @@ -10,7 +10,7 @@ # or submit itself to any jurisdiction. # NOTE!!!! - Whenever this file is changed, move it over to alidist/resources -# FindO2GPU.cmake Version 10 +# FindO2GPU.cmake Version 11 set(CUDA_COMPUTETARGET_DEFAULT_FULL 80-real 86-real 89-real 120-real 75-virtual) set(HIP_AMDGPUTARGET_DEFAULT_FULL gfx906;gfx908) @@ -173,9 +173,7 @@ if(ENABLE_CUDA) message(${FAILURE_SEVERITY} "CUDA was found but cannot be enabled") set(CMAKE_CUDA_COMPILER OFF) endif() - find_path(THRUST_INCLUDE_DIR thrust/version.h PATHS ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES} - PATH_SUFFIXES "" cccl - NO_DEFAULT_PATH) + find_path(THRUST_INCLUDE_DIR thrust/version.h PATHS ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES} PATH_SUFFIXES "" cccl NO_DEFAULT_PATH) if(THRUST_INCLUDE_DIR STREQUAL "THRUST_INCLUDE_DIR-NOTFOUND") message(${FAILURE_SEVERITY} "CUDA found but thrust not available, looked under: ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}") set(CMAKE_CUDA_COMPILER OFF) @@ -188,7 +186,7 @@ if(ENABLE_CUDA) endif() endif() if(NOT CMAKE_CUDA_ARCHITECTURES OR O2_GPU_CUDA_UPDATE_NATIVE_ARCHITECTURE) - if(NOT CMAKE_CUDA_ARCHITECTURES_NATIVE STREQUAL "") + if(NOT CMAKE_CUDA_ARCHITECTURES_NATIVE STREQUAL "" AND NOT CMAKE_CUDA_ARCHITECTURES_NATIVE MATCHES "No CUDA devices found") set(CMAKE_CUDA_ARCHITECTURES ${CMAKE_CUDA_ARCHITECTURES_NATIVE}) else() set(CMAKE_CUDA_ARCHITECTURES ${CUDA_COMPUTETARGET_DEFAULT_MINIMAL}) From 9e910d691cb379f93c7c1dc7a09ee9193cddaa06 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 5 Feb 2026 15:59:08 +0100 Subject: [PATCH 152/234] GPU: Add converter scripts for CSV parameter file to JSON and vice versa --- .../Base/cuda/GPUReconstructionCUDA.cu | 2 +- .../Definitions/Parameters/csv_to_json.sh | 46 +++++++++++++++++ .../Definitions/Parameters/json_to_csv.python | 50 +++++++++++++++++++ 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100755 GPU/GPUTracking/Definitions/Parameters/csv_to_json.sh create mode 100755 GPU/GPUTracking/Definitions/Parameters/json_to_csv.python diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu index 8e896ca513f53..c919581eefdde 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu @@ -189,7 +189,7 @@ int32_t GPUReconstructionCUDA::InitDevice_Runtime() bestDeviceSpeed = deviceSpeed; } else { if (GetProcessingSettings().debugLevel >= 2 && GetProcessingSettings().deviceNum < 0) { - GPUInfo("Skipping: Speed %f < %f\n", deviceSpeed, bestDeviceSpeed); + GPUInfo("Skipping: Speed %f <= %f\n", deviceSpeed, bestDeviceSpeed); } } } diff --git a/GPU/GPUTracking/Definitions/Parameters/csv_to_json.sh b/GPU/GPUTracking/Definitions/Parameters/csv_to_json.sh new file mode 100755 index 0000000000000..ae9d3b7704284 --- /dev/null +++ b/GPU/GPUTracking/Definitions/Parameters/csv_to_json.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +[[ -z $1 ]] && { echo "Usage: csv_to_json.sh CSV_FILE"; exit 1; } + +awk -vFPAT='([^,]*)|(\"([^\"]|\"\")*\")' \ + 'BEGIN { + print "{" + } { + if (count == 0) { + for (i = 1; i <= NF; i++) { + names[i] = $i + } + } else if ($1 == "CORE:" || $1 == "LB:" || $1 == "PAR:") { + if (paramprinted) print "\n }" + else if (lineprinted) print "" + if (catprinted) print " }," + lineprinted = 0 + paramprinted = 0 + catprinted = 1 + gsub(/:$/, "", $1) + print " \""$1"\": {"; + } else if ($1 != "") { + if (lineprinted) print "" + if (paramprinted) print " }," + lineprinted = 0 + paramprinted = 1 + print " \""$1"\": {"; + lineprinted = 0 + for (i=2; i<=NF; i++) { + if ($i != "") { + gsub(/^"/, "", $i) + gsub(/"$/, "", $i) + gsub(/""/, "\"", $i) + if (lineprinted) print "," + lineprinted = 1 + printf(" \"%s\": %s", names[i], $i) + } + } + } + count++; + } END { + if (paramprinted) print "\n }" + if (catprinted) print " }" + print "}" + }' \ + $1 diff --git a/GPU/GPUTracking/Definitions/Parameters/json_to_csv.python b/GPU/GPUTracking/Definitions/Parameters/json_to_csv.python new file mode 100755 index 0000000000000..a6640239604e0 --- /dev/null +++ b/GPU/GPUTracking/Definitions/Parameters/json_to_csv.python @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +import sys, json, csv, string + +if len(sys.argv) != 3: + sys.exit("usage: json2csv.py input.json output.csv") + +try: + data = json.load(open(sys.argv[1])) +except Exception: + sys.exit("invalid json") + +if set(data) != {"CORE", "LB", "PAR"}: + sys.exit("invalid categories") + +arches = [] +seen = set() +for cat in data.values(): + if not isinstance(cat, dict): + sys.exit("data not 2-dimensional") + for param in cat.values(): + if not isinstance(param, dict): + sys.exit("data not 2-dimensional") + for a in param.keys(): + if a not in seen: + seen.add(a) + arches.append(a) + +cols = 1 + len(arches) +empty = [""] * cols + +with open(sys.argv[2], "w", newline="") as f: + w = csv.writer(f, lineterminator="\n") + w.writerow(["Architecture", *arches]) + w.writerow(empty) + cats = list(data.items()) + for ci, (cname, cat) in enumerate(cats): + w.writerow([f"{cname}:"] + [""] * (cols - 1)) + for pname, param in cat.items(): + row = [pname] + for a in arches: + v = param.get(a, "") + if isinstance(v, list): + row.append(json.dumps(v)) + elif isinstance(v, str) and not v == "": + row.append('"' + v + '"') + else: + row.append(v) + w.writerow(row) + if ci != len(cats) - 1: + w.writerow(empty) From c8834dee0b39f86f394dfb07f5a42ab09659dffa Mon Sep 17 00:00:00 2001 From: shahoian Date: Thu, 5 Feb 2026 11:27:52 +0100 Subject: [PATCH 153/234] Promote --ctf-dict from process to workflow level option --- .../Base/include/DetectorsBase/CTFCoderBase.h | 14 ++++---- .../include/CPVReconstruction/CTFCoder.h | 2 +- .../include/CPVWorkflow/EntropyDecoderSpec.h | 4 +-- .../include/CPVWorkflow/EntropyEncoderSpec.h | 4 +-- .../CPV/workflow/src/EntropyDecoderSpec.cxx | 13 +++---- .../CPV/workflow/src/EntropyEncoderSpec.cxx | 13 +++---- .../workflow/src/entropy-encoder-workflow.cxx | 3 +- .../include/CTFWorkflow/CTFReaderSpec.h | 1 + Detectors/CTF/workflow/src/CTFReaderSpec.cxx | 1 - .../CTF/workflow/src/ctf-reader-workflow.cxx | 34 ++++++++++--------- .../include/CTPReconstruction/CTFCoder.h | 2 +- .../include/CTPWorkflow/EntropyDecoderSpec.h | 4 +-- .../include/CTPWorkflow/EntropyEncoderSpec.h | 4 +-- .../CTP/workflow/src/EntropyDecoderSpec.cxx | 16 ++++----- .../CTP/workflow/src/EntropyEncoderSpec.cxx | 16 ++++----- .../workflow/src/entropy-encoder-workflow.cxx | 3 +- .../include/EMCALReconstruction/CTFCoder.h | 2 +- .../EMCALWorkflow/EntropyDecoderSpec.h | 4 +-- .../EMCALWorkflow/EntropyEncoderSpec.h | 4 +-- .../EMCAL/workflow/src/EntropyDecoderSpec.cxx | 16 ++++----- .../EMCAL/workflow/src/EntropyEncoderSpec.cxx | 23 ++++++------- .../workflow/src/entropy-encoder-workflow.cxx | 3 +- .../include/FDDReconstruction/CTFCoder.h | 2 +- .../include/FDDWorkflow/EntropyDecoderSpec.h | 4 +-- .../include/FDDWorkflow/EntropyEncoderSpec.h | 4 +-- .../FDD/workflow/src/EntropyDecoderSpec.cxx | 16 ++++----- .../FDD/workflow/src/EntropyEncoderSpec.cxx | 16 ++++----- .../workflow/src/entropy-encoder-workflow.cxx | 3 +- .../include/FT0Reconstruction/CTFCoder.h | 2 +- .../include/FT0Workflow/EntropyDecoderSpec.h | 4 +-- .../include/FT0Workflow/EntropyEncoderSpec.h | 4 +-- .../FT0/workflow/src/EntropyDecoderSpec.cxx | 15 ++++---- .../FT0/workflow/src/EntropyEncoderSpec.cxx | 16 ++++----- .../workflow/src/entropy-encoder-workflow.cxx | 3 +- .../include/FV0Reconstruction/CTFCoder.h | 2 +- .../include/FV0Workflow/EntropyDecoderSpec.h | 4 +-- .../include/FV0Workflow/EntropyEncoderSpec.h | 4 +-- .../FV0/workflow/src/EntropyDecoderSpec.cxx | 16 ++++----- .../FV0/workflow/src/EntropyEncoderSpec.cxx | 16 ++++----- .../workflow/src/entropy-encoder-workflow.cxx | 3 +- .../include/HMPIDReconstruction/CTFCoder.h | 2 +- .../HMPIDWorkflow/EntropyDecoderSpec.h | 2 +- .../HMPIDWorkflow/EntropyEncoderSpec.h | 2 +- .../HMPID/workflow/src/EntropyDecoderSpec.cxx | 18 +++++----- .../HMPID/workflow/src/EntropyEncoderSpec.cxx | 18 +++++----- .../workflow/src/entropy-encoder-workflow.cxx | 3 +- .../include/ITSMFTReconstruction/CTFCoder.h | 2 +- .../ITSMFTWorkflow/EntropyDecoderSpec.h | 4 +-- .../ITSMFTWorkflow/EntropyEncoderSpec.h | 4 +-- .../workflow/src/EntropyDecoderSpec.cxx | 22 ++++++------ .../workflow/src/EntropyEncoderSpec.cxx | 18 +++++----- .../workflow/src/entropy-encoder-workflow.cxx | 3 +- .../MUON/MCH/CTF/include/MCHCTF/CTFCoder.h | 2 +- .../CTF/include/MCHCTF/EntropyDecoderSpec.h | 2 +- .../MUON/MCH/CTF/src/EntropyDecoderSpec.cxx | 18 +++++----- .../Workflow/src/entropy-encoder-workflow.cxx | 21 ++++++------ .../MUON/MID/CTF/include/MIDCTF/CTFCoder.h | 2 +- .../include/MIDWorkflow/EntropyDecoderSpec.h | 4 +-- .../include/MIDWorkflow/EntropyEncoderSpec.h | 4 +-- .../MID/Workflow/src/EntropyDecoderSpec.cxx | 16 ++++----- .../MID/Workflow/src/EntropyEncoderSpec.cxx | 16 ++++----- .../Workflow/src/entropy-encoder-workflow.cxx | 3 +- .../include/PHOSReconstruction/CTFCoder.h | 2 +- .../include/PHOSWorkflow/EntropyDecoderSpec.h | 4 +-- .../include/PHOSWorkflow/EntropyEncoderSpec.h | 4 +-- .../PHOS/workflow/src/EntropyDecoderSpec.cxx | 16 ++++----- .../PHOS/workflow/src/EntropyEncoderSpec.cxx | 16 ++++----- .../workflow/src/entropy-encoder-workflow.cxx | 3 +- .../include/TOFReconstruction/CTFCoder.h | 2 +- .../TOFWorkflowUtils/EntropyDecoderSpec.h | 4 +-- .../TOFWorkflowUtils/EntropyEncoderSpec.h | 4 +-- .../TOF/workflow/src/EntropyDecoderSpec.cxx | 16 ++++----- .../TOF/workflow/src/EntropyEncoderSpec.cxx | 16 ++++----- .../workflow/src/entropy-encoder-workflow.cxx | 3 +- .../include/TPCReconstruction/CTFCoder.h | 2 +- .../include/TPCWorkflow/EntropyDecoderSpec.h | 4 +-- .../include/TPCWorkflow/EntropyEncoderSpec.h | 4 +-- .../include/TPCWorkflow/RecoWorkflow.h | 1 + .../TPC/workflow/src/EntropyDecoderSpec.cxx | 14 ++++---- .../TPC/workflow/src/EntropyEncoderSpec.cxx | 16 ++++----- Detectors/TPC/workflow/src/RecoWorkflow.cxx | 4 +-- .../workflow/src/entropy-encoder-workflow.cxx | 3 +- .../TPC/workflow/src/tpc-reco-workflow.cxx | 2 ++ .../include/TRDReconstruction/CTFCoder.h | 2 +- .../include/TRDWorkflow/EntropyDecoderSpec.h | 2 +- .../include/TRDWorkflow/EntropyEncoderSpec.h | 2 +- .../TRD/workflow/src/EntropyDecoderSpec.cxx | 18 +++++----- .../TRD/workflow/src/EntropyEncoderSpec.cxx | 18 +++++----- .../workflow/src/entropy-encoder-workflow.cxx | 3 +- .../include/ZDCReconstruction/CTFCoder.h | 2 +- .../include/ZDCWorkflow/EntropyDecoderSpec.h | 4 +-- .../include/ZDCWorkflow/EntropyEncoderSpec.h | 4 +-- .../ZDC/workflow/src/EntropyDecoderSpec.cxx | 16 ++++----- .../ZDC/workflow/src/EntropyEncoderSpec.cxx | 16 ++++----- .../workflow/src/entropy-encoder-workflow.cxx | 3 +- 95 files changed, 378 insertions(+), 358 deletions(-) diff --git a/Detectors/Base/include/DetectorsBase/CTFCoderBase.h b/Detectors/Base/include/DetectorsBase/CTFCoderBase.h index bf4f37ecbeff5..593bf37df5879 100644 --- a/Detectors/Base/include/DetectorsBase/CTFCoderBase.h +++ b/Detectors/Base/include/DetectorsBase/CTFCoderBase.h @@ -58,8 +58,8 @@ class CTFCoderBase Decoder }; CTFCoderBase() = delete; - CTFCoderBase(int n, DetID det, float memFactor = 1.f) : mCoders(n), mDet(det), mMemMarginFactor(memFactor > 1.f ? memFactor : 1.f) {} - CTFCoderBase(OpType op, int n, DetID det, float memFactor = 1.f) : mOpType(op), mCoders(n), mDet(det), mMemMarginFactor(memFactor > 1.f ? memFactor : 1.f) {} + CTFCoderBase(int n, DetID det, float memFactor = 1.f, const std::string& ctfdictOpt = "none") : mCoders(n), mDet(det), mMemMarginFactor(memFactor > 1.f ? memFactor : 1.f), mDictOpt{ctfdictOpt} {} + CTFCoderBase(OpType op, int n, DetID det, float memFactor = 1.f, const std::string& ctfdictOpt = "none") : mOpType(op), mCoders(n), mDet(det), mMemMarginFactor(memFactor > 1.f ? memFactor : 1.f), mDictOpt{ctfdictOpt} {} virtual ~CTFCoderBase() = default; virtual void createCoders(const std::vector& bufVec, o2::ctf::CTFCoderBase::OpType op) = 0; @@ -189,6 +189,7 @@ class CTFCoderBase std::vector loadDictionaryFromTree(TTree* tree); std::vector mCoders; // encoders/decoders DetID mDet; + std::string mDictOpt{}; std::string mDictBinding{"ctfdict"}; std::string mTrigOffsBinding{"trigoffset"}; CTFDictHeader mExtHeader; // external dictionary header @@ -325,13 +326,12 @@ void CTFCoderBase::init(o2::framework::InitContext& ic) } } } - auto dict = ic.options().get("ctf-dict"); - if (dict.empty() || dict == "ccdb") { // load from CCDB + if (mDictOpt.empty() || mDictOpt == "ccdb") { // load from CCDB mLoadDictFromCCDB = true; } else { - if (dict != "none") { // none means per-CTF dictionary will created on the fly - createCodersFromFile(dict, mOpType); - LOGP(info, "Loaded {} from {}", mExtHeader.asString(), dict); + if (mDictOpt != "none") { // none means per-CTF dictionary will created on the fly + createCodersFromFile(mDictOpt, mOpType); + LOGP(info, "Loaded {} from {}", mExtHeader.asString(), mDictOpt); } else { LOGP(info, "Internal per-TF CTF Dict will be created"); } diff --git a/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFCoder.h b/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFCoder.h index ab5082b5c748c..a5f9d0eac90e8 100644 --- a/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFCoder.h +++ b/Detectors/CPV/reconstruction/include/CPVReconstruction/CTFCoder.h @@ -35,7 +35,7 @@ namespace cpv class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::CPV) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), 1.f, o2::detectors::DetID::CPV, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode data to buffer with CTF diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/EntropyDecoderSpec.h b/Detectors/CPV/workflow/include/CPVWorkflow/EntropyDecoderSpec.h index 09de778360d74..7192b1b2f6353 100644 --- a/Detectors/CPV/workflow/include/CPVWorkflow/EntropyDecoderSpec.h +++ b/Detectors/CPV/workflow/include/CPVWorkflow/EntropyDecoderSpec.h @@ -28,7 +28,7 @@ namespace cpv class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -41,7 +41,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt); } // namespace cpv } // namespace o2 diff --git a/Detectors/CPV/workflow/include/CPVWorkflow/EntropyEncoderSpec.h b/Detectors/CPV/workflow/include/CPVWorkflow/EntropyEncoderSpec.h index 24c229179fe1d..a1851ebb97377 100644 --- a/Detectors/CPV/workflow/include/CPVWorkflow/EntropyEncoderSpec.h +++ b/Detectors/CPV/workflow/include/CPVWorkflow/EntropyEncoderSpec.h @@ -28,7 +28,7 @@ namespace cpv class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR = false); + EntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -42,7 +42,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace cpv } // namespace o2 diff --git a/Detectors/CPV/workflow/src/EntropyDecoderSpec.cxx b/Detectors/CPV/workflow/src/EntropyDecoderSpec.cxx index 7c14dc70dd430..518a646e23cb9 100644 --- a/Detectors/CPV/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/CPV/workflow/src/EntropyDecoderSpec.cxx @@ -25,7 +25,7 @@ namespace o2 namespace cpv { -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); @@ -74,7 +74,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"triggers"}, "CPV", "CLUSTERTRIGRECS", 0, Lifetime::Timeframe}, @@ -83,16 +83,17 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) std::vector inputs; inputs.emplace_back("ctf_CPV", "CPV", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_CPV", "CPV", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("CPV/Calib/CTFDictionaryTree")); + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_CPV", "CPV", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("CPV/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ "cpv-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } } // namespace cpv diff --git a/Detectors/CPV/workflow/src/EntropyEncoderSpec.cxx b/Detectors/CPV/workflow/src/EntropyEncoderSpec.cxx index 31ed720e66335..54fb1354ad60c 100644 --- a/Detectors/CPV/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/CPV/workflow/src/EntropyEncoderSpec.cxx @@ -26,7 +26,7 @@ namespace o2 namespace cpv { -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -70,12 +70,14 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("triggers", "CPV", "CLUSTERTRIGRECS", 0, Lifetime::Timeframe); inputs.emplace_back("clusters", "CPV", "CLUSTERS", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "CPV", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("CPV/Calib/CTFDictionaryTree")); + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "CPV", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("CPV/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -84,9 +86,8 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR) inputs, Outputs{{"CPV", "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, "CPV", "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; diff --git a/Detectors/CPV/workflow/src/entropy-encoder-workflow.cxx b/Detectors/CPV/workflow/src/entropy-encoder-workflow.cxx index d7e79c4cea430..6f9445d9ddd16 100644 --- a/Detectors/CPV/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/CPV/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -37,6 +38,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::cpv::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"))); + wf.emplace_back(o2::cpv::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h b/Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h index ab03649c0646b..081e6cf4d968a 100644 --- a/Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h +++ b/Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h @@ -32,6 +32,7 @@ struct CTFReaderInp { std::string metricChannel{}; std::string fileIRFrames{}; std::string fileRunTimeSpans{}; + std::string dictOpt{}; std::vector ctfIDs{}; bool reverseCTFIDs{false}; bool skipSkimmedOutTF = false; diff --git a/Detectors/CTF/workflow/src/CTFReaderSpec.cxx b/Detectors/CTF/workflow/src/CTFReaderSpec.cxx index 3810230637e5f..4100ebb37c61d 100644 --- a/Detectors/CTF/workflow/src/CTFReaderSpec.cxx +++ b/Detectors/CTF/workflow/src/CTFReaderSpec.cxx @@ -645,7 +645,6 @@ DataProcessorSpec getCTFReaderSpec(const CTFReaderInp& inp) if (!inp.sup0xccdb) { outputs.emplace_back(OutputSpec{{"TFDist"}, o2::header::gDataOriginFLP, o2::header::gDataDescriptionDISTSTF, 0xccdb}); } - options.emplace_back(ConfigParamSpec{"select-ctf-ids", VariantType::String, "", {"comma-separated list CTF IDs to inject (from cumulative counter of CTFs seen)"}}); options.emplace_back(ConfigParamSpec{"reverse-select-ctf-ids", VariantType::Bool, false, {"reverse order of to inject CTF IDs"}}); options.emplace_back(ConfigParamSpec{"impose-run-start-timstamp", VariantType::Int64, 0L, {"impose run start time stamp (ms), ignored if 0"}}); diff --git a/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx b/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx index cddf694251a01..fc50c971c5d20 100644 --- a/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx +++ b/Detectors/CTF/workflow/src/ctf-reader-workflow.cxx @@ -52,6 +52,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options; options.push_back(ConfigParamSpec{"ctf-input", VariantType::String, "none", {"comma-separated list CTF input files"}}); + options.push_back(ConfigParamSpec{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}); options.push_back(ConfigParamSpec{"onlyDet", VariantType::String, std::string{DetID::ALL}, {"comma-separated list of detectors to accept. Overrides skipDet"}}); options.push_back(ConfigParamSpec{"skipDet", VariantType::String, std::string{DetID::NONE}, {"comma-separate list of detectors to skip"}}); options.push_back(ConfigParamSpec{"loop", VariantType::Int, 0, {"loop N times (infinite for N<0)"}}); @@ -132,6 +133,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) ctfInput.fileRunTimeSpans = configcontext.options().get("run-time-span-file"); ctfInput.skipSkimmedOutTF = configcontext.options().get("skip-skimmed-out-tf"); ctfInput.invertIRFramesSelection = configcontext.options().get("invert-irframe-selection"); + ctfInput.dictOpt = configcontext.options().get("ctf-dict"); int verbosity = configcontext.options().get("ctf-reader-verbosity"); int rateLimitingIPCID = std::stoi(configcontext.options().get("timeframes-rate-limit-ipcid")); @@ -181,52 +183,52 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // add decoders for all allowed detectors. if (ctfInput.detMask[DetID::ITS]) { - addSpecs(o2::itsmft::getEntropyDecoderSpec(DetID::getDataOrigin(DetID::ITS), verbosity, configcontext.options().get("its-digits"), ctfInput.subspec)); + addSpecs(o2::itsmft::getEntropyDecoderSpec(DetID::getDataOrigin(DetID::ITS), verbosity, configcontext.options().get("its-digits"), ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::MFT]) { - addSpecs(o2::itsmft::getEntropyDecoderSpec(DetID::getDataOrigin(DetID::MFT), verbosity, configcontext.options().get("mft-digits"), ctfInput.subspec)); + addSpecs(o2::itsmft::getEntropyDecoderSpec(DetID::getDataOrigin(DetID::MFT), verbosity, configcontext.options().get("mft-digits"), ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::TPC]) { - addSpecs(o2::tpc::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::tpc::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::TRD]) { - addSpecs(o2::trd::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::trd::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::TOF]) { - addSpecs(o2::tof::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::tof::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::FT0]) { - addSpecs(o2::ft0::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::ft0::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::FV0]) { - addSpecs(o2::fv0::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::fv0::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::FDD]) { - addSpecs(o2::fdd::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::fdd::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::MID]) { - addSpecs(o2::mid::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::mid::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::MCH]) { - addSpecs(o2::mch::getEntropyDecoderSpec(verbosity, "mch-entropy-decoder", ctfInput.subspec)); + addSpecs(o2::mch::getEntropyDecoderSpec(verbosity, "mch-entropy-decoder", ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::EMC]) { - addSpecs(o2::emcal::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.decSSpecEMC)); + addSpecs(o2::emcal::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.decSSpecEMC, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::PHS]) { - addSpecs(o2::phos::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::phos::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::CPV]) { - addSpecs(o2::cpv::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::cpv::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::ZDC]) { - addSpecs(o2::zdc::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::zdc::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::HMP]) { - addSpecs(o2::hmpid::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::hmpid::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } if (ctfInput.detMask[DetID::CTP]) { - addSpecs(o2::ctp::getEntropyDecoderSpec(verbosity, ctfInput.subspec)); + addSpecs(o2::ctp::getEntropyDecoderSpec(verbosity, ctfInput.subspec, ctfInput.dictOpt)); } bool combine = configcontext.options().get("combine-devices"); diff --git a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h index 87657f6a6f8c6..b17db0e77be28 100644 --- a/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h +++ b/Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h @@ -37,7 +37,7 @@ namespace ctp class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::CTP) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), 1.f, o2::detectors::DetID::CTP, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode data to buffer with CTF diff --git a/Detectors/CTP/workflow/include/CTPWorkflow/EntropyDecoderSpec.h b/Detectors/CTP/workflow/include/CTPWorkflow/EntropyDecoderSpec.h index eee7abb08d16c..dda45c9f11a34 100644 --- a/Detectors/CTP/workflow/include/CTPWorkflow/EntropyDecoderSpec.h +++ b/Detectors/CTP/workflow/include/CTPWorkflow/EntropyDecoderSpec.h @@ -28,7 +28,7 @@ namespace ctp class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -42,7 +42,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt); } // namespace ctp } // namespace o2 diff --git a/Detectors/CTP/workflow/include/CTPWorkflow/EntropyEncoderSpec.h b/Detectors/CTP/workflow/include/CTPWorkflow/EntropyEncoderSpec.h index 3a023ce2022dc..a63119264e071 100644 --- a/Detectors/CTP/workflow/include/CTPWorkflow/EntropyEncoderSpec.h +++ b/Detectors/CTP/workflow/include/CTPWorkflow/EntropyEncoderSpec.h @@ -28,7 +28,7 @@ namespace ctp class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR, bool noLumi); + EntropyEncoderSpec(bool selIR, bool noLumi, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -43,7 +43,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, bool noLumiInput = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, bool noLumiInput = false, const std::string& ctfdictOpt = "none"); } // namespace ctp } // namespace o2 diff --git a/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx b/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx index 8c2f5d05aa031..0fa8fb0004e4c 100644 --- a/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx @@ -24,8 +24,7 @@ namespace o2 { namespace ctp { - -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); @@ -90,7 +89,7 @@ void EntropyDecoderSpec::updateTimeDependentParams(framework::ProcessingContext& } } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"digits"}, "CTP", "DIGITS", 0, Lifetime::Timeframe}, @@ -99,18 +98,19 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) std::vector inputs; inputs.emplace_back("ctf_CTP", "CTP", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_CTP", "CTP", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("CTP/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_CTP", "CTP", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("CTP/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); inputs.emplace_back("ctpconfig", "CTP", "CTPCONFIG", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/Config", 1)); return DataProcessorSpec{ "ctp-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ignore-ctpinputs-decoding-ctf", VariantType::Bool, false, {"Inputs alignment: false - CTF decoder - has to be compatible with reco: allowed options: 10,01,00"}}, + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ignore-ctpinputs-decoding-ctf", VariantType::Bool, false, {"Inputs alignment: false - CTF decoder - has to be compatible with reco: allowed options: 10,01,00"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace ctp } // namespace o2 diff --git a/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx b/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx index 44e64d7505977..902fe22dadcc9 100644 --- a/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx @@ -25,8 +25,7 @@ namespace o2 { namespace ctp { - -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, bool nolumi) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR), mNoLumi(nolumi) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, bool nolumi, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR), mNoLumi(nolumi) { mTimer.Stop(); mTimer.Reset(); @@ -77,14 +76,17 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR, bool nolumi) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, bool nolumi, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("digits", "CTP", "DIGITS", 0, Lifetime::Timeframe); if (!nolumi) { inputs.emplace_back("CTPLumi", "CTP", "LUMI", 0, Lifetime::Timeframe); } - inputs.emplace_back("ctfdict", "CTP", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("CTP/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "CTP", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("CTP/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -92,13 +94,11 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR, bool nolumi) "ctp-entropy-encoder", inputs, Outputs{{"CTP", "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, "CTP", "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR, nolumi)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, nolumi, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace ctp } // namespace o2 diff --git a/Detectors/CTP/workflow/src/entropy-encoder-workflow.cxx b/Detectors/CTP/workflow/src/entropy-encoder-workflow.cxx index 1fcaa89be9888..9057d16df4384 100644 --- a/Detectors/CTP/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/CTP/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"no-lumi-input", VariantType::Bool, false, {"Lumi info not available"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; @@ -38,6 +39,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::ctp::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("no-lumi-input"))); + wf.emplace_back(o2::ctp::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("no-lumi-input"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h index 23deb75ffb049..6584775057d9f 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h @@ -35,7 +35,7 @@ namespace emcal class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::EMC) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), 1.f, o2::detectors::DetID::EMC, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode data to buffer with CTF diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyDecoderSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyDecoderSpec.h index 0215e0ae65e43..9cc5ba7887473 100644 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyDecoderSpec.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyDecoderSpec.h @@ -28,7 +28,7 @@ namespace emcal class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity, unsigned int sspecOut); + EntropyDecoderSpec(int verbosity, unsigned int sspecOut, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -42,7 +42,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspecInp, unsigned int sspecOut = 0); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspecInp, unsigned int sspecOut = 0, const std::string& ctfdictOpt = "none"); } // namespace emcal } // namespace o2 diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyEncoderSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyEncoderSpec.h index cdfb342e7ff11..df502beef30df 100644 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyEncoderSpec.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyEncoderSpec.h @@ -28,7 +28,7 @@ namespace emcal class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR); + EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -42,7 +42,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace emcal } // namespace o2 diff --git a/Detectors/EMCAL/workflow/src/EntropyDecoderSpec.cxx b/Detectors/EMCAL/workflow/src/EntropyDecoderSpec.cxx index 700f468e9e73d..ecc0e45492bea 100644 --- a/Detectors/EMCAL/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/EMCAL/workflow/src/EntropyDecoderSpec.cxx @@ -24,8 +24,7 @@ namespace o2 { namespace emcal { - -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, unsigned int sspecOut) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder), mSSpecOut(sspecOut) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, unsigned int sspecOut, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt), mSSpecOut(sspecOut) { mTimer.Stop(); mTimer.Reset(); @@ -74,7 +73,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspecInp, unsigned int sspecOut) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspecInp, unsigned int sspecOut, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"triggers"}, "EMC", "CELLSTRGR", sspecOut, Lifetime::Timeframe}, @@ -83,17 +82,18 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspecInp, un std::vector inputs; inputs.emplace_back("ctf_EMC", "EMC", "CTFDATA", sspecInp, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_EMC", "EMC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("EMC/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_EMC", "EMC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("EMC/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ "emcal-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity, sspecOut)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, sspecOut, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace emcal } // namespace o2 diff --git a/Detectors/EMCAL/workflow/src/EntropyEncoderSpec.cxx b/Detectors/EMCAL/workflow/src/EntropyEncoderSpec.cxx index 773c4c65fc9fe..2928a71a167bc 100644 --- a/Detectors/EMCAL/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/EMCAL/workflow/src/EntropyEncoderSpec.cxx @@ -25,8 +25,7 @@ namespace o2 { namespace emcal { - -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -71,12 +70,15 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("triggers", "EMC", "CELLSTRGR", 0, Lifetime::Timeframe); inputs.emplace_back("cells", "EMC", "CELLS", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "EMC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("EMC/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "EMC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("EMC/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -85,14 +87,11 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR) inputs, Outputs{{"EMC", "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, "EMC", "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{ - {"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, - {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, - {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, + {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, + {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace emcal } // namespace o2 diff --git a/Detectors/EMCAL/workflow/src/entropy-encoder-workflow.cxx b/Detectors/EMCAL/workflow/src/entropy-encoder-workflow.cxx index e6af02fa10d49..953b726fcb971 100644 --- a/Detectors/EMCAL/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/EMCAL/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -37,6 +38,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::emcal::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"))); + wf.emplace_back(o2::emcal::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/CTFCoder.h b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/CTFCoder.h index 94a0c6f64659d..cb3b13aa9b8e4 100644 --- a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/CTFCoder.h +++ b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/CTFCoder.h @@ -36,7 +36,7 @@ namespace fdd class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::FDD) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), 1.f, o2::detectors::DetID::FDD, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode digits to buffer with CTF diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyDecoderSpec.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyDecoderSpec.h index a6ee132ee0c34..1fd3cd7835cd9 100644 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyDecoderSpec.h +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyDecoderSpec.h @@ -28,7 +28,7 @@ namespace fdd class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -41,7 +41,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt); } // namespace fdd } // namespace o2 diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyEncoderSpec.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyEncoderSpec.h index 87dcca02e869f..37d43f477e836 100644 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyEncoderSpec.h +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyEncoderSpec.h @@ -28,7 +28,7 @@ namespace fdd class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR); + EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -42,7 +42,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace fdd } // namespace o2 diff --git a/Detectors/FIT/FDD/workflow/src/EntropyDecoderSpec.cxx b/Detectors/FIT/FDD/workflow/src/EntropyDecoderSpec.cxx index fb5b173fb7a94..33c140b5bc198 100644 --- a/Detectors/FIT/FDD/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/FIT/FDD/workflow/src/EntropyDecoderSpec.cxx @@ -24,8 +24,7 @@ namespace o2 { namespace fdd { - -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); @@ -73,7 +72,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"digits"}, "FDD", "DIGITSBC", 0, Lifetime::Timeframe}, @@ -82,17 +81,18 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) std::vector inputs; inputs.emplace_back("ctf_FDD", "FDD", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_FDD", "FDD", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FDD/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_FDD", "FDD", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FDD/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ "fdd-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace fdd } // namespace o2 diff --git a/Detectors/FIT/FDD/workflow/src/EntropyEncoderSpec.cxx b/Detectors/FIT/FDD/workflow/src/EntropyEncoderSpec.cxx index abb2518e5ae0b..be81f7ca7d3d4 100644 --- a/Detectors/FIT/FDD/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/FIT/FDD/workflow/src/EntropyEncoderSpec.cxx @@ -25,8 +25,7 @@ namespace o2 { namespace fdd { - -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -69,12 +68,15 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("digits", "FDD", "DIGITSBC", 0, Lifetime::Timeframe); inputs.emplace_back("channels", "FDD", "DIGITSCH", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "FDD", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FDD/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "FDD", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FDD/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -82,13 +84,11 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR) "fdd-entropy-encoder", inputs, Outputs{{"FDD", "CTFDATA", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace fdd } // namespace o2 diff --git a/Detectors/FIT/FDD/workflow/src/entropy-encoder-workflow.cxx b/Detectors/FIT/FDD/workflow/src/entropy-encoder-workflow.cxx index bcc42ebc2e086..0e43c6e3c4ba0 100644 --- a/Detectors/FIT/FDD/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/FIT/FDD/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -37,6 +38,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::fdd::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"))); + wf.emplace_back(o2::fdd::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h index 65646c161dde5..5c2e0f0627ef1 100644 --- a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h +++ b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h @@ -37,7 +37,7 @@ namespace ft0 class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::FT0) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), 1.f, o2::detectors::DetID::FT0, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode digits to buffer with CTF diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyDecoderSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyDecoderSpec.h index 4f8e8b5e9be63..d6009accfa45b 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyDecoderSpec.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyDecoderSpec.h @@ -28,7 +28,7 @@ namespace ft0 class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -41,7 +41,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt); } // namespace ft0 } // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyEncoderSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyEncoderSpec.h index 8fd597af8629d..a1b3714fdbb26 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyEncoderSpec.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyEncoderSpec.h @@ -28,7 +28,7 @@ namespace ft0 class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR); + EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -42,7 +42,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace ft0 } // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/src/EntropyDecoderSpec.cxx b/Detectors/FIT/FT0/workflow/src/EntropyDecoderSpec.cxx index 65d3585350888..066c5cc547c2e 100644 --- a/Detectors/FIT/FT0/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/EntropyDecoderSpec.cxx @@ -24,8 +24,7 @@ namespace o2 { namespace ft0 { - -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); @@ -73,7 +72,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"digits"}, "FT0", "DIGITSBC", 0, Lifetime::Timeframe}, @@ -82,16 +81,18 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) std::vector inputs; inputs.emplace_back("ctf_FT0", "FT0", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_FT0", "FT0", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FT0/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_FT0", "FT0", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FT0/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ "ft0-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace ft0 } // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/src/EntropyEncoderSpec.cxx b/Detectors/FIT/FT0/workflow/src/EntropyEncoderSpec.cxx index 81bdc2e729bb4..7be6618a61103 100644 --- a/Detectors/FIT/FT0/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/EntropyEncoderSpec.cxx @@ -25,8 +25,7 @@ namespace o2 { namespace ft0 { - -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -70,12 +69,15 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("digits", "FT0", "DIGITSBC", 0, Lifetime::Timeframe); inputs.emplace_back("channels", "FT0", "DIGITSCH", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "FT0", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FT0/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "FT0", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FT0/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -83,13 +85,11 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR) "ft0-entropy-encoder", inputs, Outputs{{"FT0", "CTFDATA", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace ft0 } // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/src/entropy-encoder-workflow.cxx b/Detectors/FIT/FT0/workflow/src/entropy-encoder-workflow.cxx index 6a98bbdafd53b..2b4a86df0a614 100644 --- a/Detectors/FIT/FT0/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/FIT/FT0/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -37,6 +38,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::ft0::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"))); + wf.emplace_back(o2::ft0::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h b/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h index 4398e19c0a5ed..fdff035b934ef 100644 --- a/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h +++ b/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h @@ -33,7 +33,7 @@ namespace fv0 class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::FV0) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), 1.f, o2::detectors::DetID::FV0, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode digits to buffer with CTF diff --git a/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyDecoderSpec.h b/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyDecoderSpec.h index 67b74f45e42bf..76f1aae5e728d 100644 --- a/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyDecoderSpec.h +++ b/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyDecoderSpec.h @@ -28,7 +28,7 @@ namespace fv0 class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -41,7 +41,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt); } // namespace fv0 } // namespace o2 diff --git a/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyEncoderSpec.h b/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyEncoderSpec.h index db4f154a302c7..0df9403a88a12 100644 --- a/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyEncoderSpec.h +++ b/Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyEncoderSpec.h @@ -28,7 +28,7 @@ namespace fv0 class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR); + EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -42,7 +42,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace fv0 } // namespace o2 diff --git a/Detectors/FIT/FV0/workflow/src/EntropyDecoderSpec.cxx b/Detectors/FIT/FV0/workflow/src/EntropyDecoderSpec.cxx index 9310905ad41b9..7babe9fdea6ed 100644 --- a/Detectors/FIT/FV0/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/FIT/FV0/workflow/src/EntropyDecoderSpec.cxx @@ -24,8 +24,7 @@ namespace o2 { namespace fv0 { - -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); @@ -73,7 +72,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"digits"}, "FV0", "DIGITSBC", 0, Lifetime::Timeframe}, @@ -82,17 +81,18 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) std::vector inputs; inputs.emplace_back("ctf_FV0", "FV0", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_FV0", "FV0", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FV0/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_FV0", "FV0", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FV0/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ "fv0-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace fv0 } // namespace o2 diff --git a/Detectors/FIT/FV0/workflow/src/EntropyEncoderSpec.cxx b/Detectors/FIT/FV0/workflow/src/EntropyEncoderSpec.cxx index a25c16a5d697c..2448af09fac4e 100644 --- a/Detectors/FIT/FV0/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/FIT/FV0/workflow/src/EntropyEncoderSpec.cxx @@ -25,8 +25,7 @@ namespace o2 { namespace fv0 { - -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -71,12 +70,15 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("digits", "FV0", "DIGITSBC", 0, Lifetime::Timeframe); inputs.emplace_back("channels", "FV0", "DIGITSCH", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "FV0", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FV0/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "FV0", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("FV0/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -85,13 +87,11 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR) inputs, Outputs{{"FV0", "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, "FV0", "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace fv0 } // namespace o2 diff --git a/Detectors/FIT/FV0/workflow/src/entropy-encoder-workflow.cxx b/Detectors/FIT/FV0/workflow/src/entropy-encoder-workflow.cxx index 90f37996b55b7..f1b1bfa456316 100644 --- a/Detectors/FIT/FV0/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/FIT/FV0/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -37,6 +38,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::fv0::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"))); + wf.emplace_back(o2::fv0::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFCoder.h b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFCoder.h index 39242355a3de9..0e6694d2353ac 100644 --- a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFCoder.h +++ b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFCoder.h @@ -35,7 +35,7 @@ namespace hmpid class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::HMP) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), 1.f, o2::detectors::DetID::HMP, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode data to buffer with CTF diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyDecoderSpec.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyDecoderSpec.h index 8c64f326a6878..d03a30ab905e5 100644 --- a/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyDecoderSpec.h +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyDecoderSpec.h @@ -24,7 +24,7 @@ namespace hmpid { /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt = "none"); } // namespace hmpid } // namespace o2 diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyEncoderSpec.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyEncoderSpec.h index 2fb9fd301f13b..9c2c4eb5b4fb0 100644 --- a/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyEncoderSpec.h +++ b/Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyEncoderSpec.h @@ -24,7 +24,7 @@ namespace hmpid { /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace hmpid } // namespace o2 diff --git a/Detectors/HMPID/workflow/src/EntropyDecoderSpec.cxx b/Detectors/HMPID/workflow/src/EntropyDecoderSpec.cxx index aa22979bc305f..9ec05efc846fb 100644 --- a/Detectors/HMPID/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/HMPID/workflow/src/EntropyDecoderSpec.cxx @@ -26,11 +26,10 @@ namespace o2 { namespace hmpid { - class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -42,7 +41,7 @@ class EntropyDecoderSpec : public o2::framework::Task TStopwatch mTimer; }; -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); @@ -91,7 +90,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"triggers"}, "HMP", "INTRECORDS", 0, Lifetime::Timeframe}, @@ -100,17 +99,18 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) std::vector inputs; inputs.emplace_back("ctf_HMP", "HMP", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_HMP", "HMP", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("HMP/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_HMP", "HMP", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("HMP/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ "hmpid-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace hmpid } // namespace o2 diff --git a/Detectors/HMPID/workflow/src/EntropyEncoderSpec.cxx b/Detectors/HMPID/workflow/src/EntropyEncoderSpec.cxx index 95723f42d0fd6..c29c1cee459bc 100644 --- a/Detectors/HMPID/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/HMPID/workflow/src/EntropyEncoderSpec.cxx @@ -27,11 +27,10 @@ namespace o2 { namespace hmpid { - class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR = false); + EntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -44,7 +43,7 @@ class EntropyEncoderSpec : public o2::framework::Task TStopwatch mTimer; }; -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -89,12 +88,15 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("triggers", "HMP", "INTRECORDS", 0, Lifetime::Timeframe); inputs.emplace_back("digits", "HMP", "DIGITS", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "HMP", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("HMP/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "HMP", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("HMP/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -103,13 +105,11 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR) inputs, Outputs{{"HMP", "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, "HMP", "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace hmpid } // namespace o2 diff --git a/Detectors/HMPID/workflow/src/entropy-encoder-workflow.cxx b/Detectors/HMPID/workflow/src/entropy-encoder-workflow.cxx index fde5e0183abd6..76e7eae10508e 100644 --- a/Detectors/HMPID/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/HMPID/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -37,6 +38,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::hmpid::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"))); + wf.emplace_back(o2::hmpid::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/CTFCoder.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/CTFCoder.h index 94c14424f6ce3..57d989038342a 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/CTFCoder.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/CTFCoder.h @@ -45,7 +45,7 @@ class CTFCoder final : public o2::ctf::CTFCoderBase using PMatrix = std::array, ClusterPattern::MaxColSpan + 2>; using RowColBuff = std::vector; - CTFCoder(o2::ctf::CTFCoderBase::OpType op, o2::detectors::DetID det) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), det) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, o2::detectors::DetID det, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), 1.f, det, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode clusters to buffer with CTF diff --git a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyDecoderSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyDecoderSpec.h index 4ed4e99f4b6f8..a64f2bf8c063c 100644 --- a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyDecoderSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyDecoderSpec.h @@ -32,7 +32,7 @@ namespace itsmft class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(o2::header::DataOrigin orig, int verbosity, bool getDigits = false); + EntropyDecoderSpec(o2::header::DataOrigin orig, int verbosity, bool getDigits = false, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void init(o2::framework::InitContext& ic) final; void run(o2::framework::ProcessingContext& pc) final; @@ -60,7 +60,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(o2::header::DataOrigin orig, int verbosity, bool getDigits, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(o2::header::DataOrigin orig, int verbosity, bool getDigits, unsigned int sspec, const std::string& ctfdictOpt); } // namespace itsmft } // namespace o2 diff --git a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyEncoderSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyEncoderSpec.h index c10ae16c95a3e..588cae6339489 100644 --- a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyEncoderSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyEncoderSpec.h @@ -30,7 +30,7 @@ namespace itsmft class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(o2::header::DataOrigin orig, bool selIR); + EntropyEncoderSpec(o2::header::DataOrigin orig, bool selIR, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -48,7 +48,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(o2::header::DataOrigin orig, bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(o2::header::DataOrigin orig, bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace itsmft } // namespace o2 diff --git a/Detectors/ITSMFT/common/workflow/src/EntropyDecoderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/EntropyDecoderSpec.cxx index 4edbc10d5bfbd..f90b708af1996 100644 --- a/Detectors/ITSMFT/common/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/EntropyDecoderSpec.cxx @@ -28,9 +28,8 @@ namespace o2 { namespace itsmft { - -EntropyDecoderSpec::EntropyDecoderSpec(o2::header::DataOrigin orig, int verbosity, bool getDigits) - : mOrigin(orig), mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, orig == o2::header::gDataOriginITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT), mGetDigits(getDigits) +EntropyDecoderSpec::EntropyDecoderSpec(o2::header::DataOrigin orig, int verbosity, bool getDigits, const std::string& ctfdictOpt) + : mOrigin(orig), mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, orig == o2::header::gDataOriginITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT, ctfdictOpt), mGetDigits(getDigits) { assert(orig == o2::header::gDataOriginITS || orig == o2::header::gDataOriginMFT); mDetPrefix = orig == o2::header::gDataOriginITS ? "_ITS" : "_MFT"; @@ -119,7 +118,7 @@ void EntropyDecoderSpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& matche } } -DataProcessorSpec getEntropyDecoderSpec(o2::header::DataOrigin orig, int verbosity, bool getDigits, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(o2::header::DataOrigin orig, int verbosity, bool getDigits, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs; // this is a special dummy input which makes sense only in sync workflows @@ -141,20 +140,19 @@ DataProcessorSpec getEntropyDecoderSpec(o2::header::DataOrigin orig, int verbosi inputs.emplace_back(std::string("ctf") + nm, orig, "CTFDATA", sspec, Lifetime::Timeframe); inputs.emplace_back(std::string("noise") + nm, orig, "NOISEMAP", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Calib/NoiseMap", orig.as()))); inputs.emplace_back(std::string("cldict") + nm, orig, "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Calib/ClusterDictionary", orig.as()))); - inputs.emplace_back(std::string("ctfdict") + nm, orig, "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Calib/CTFDictionaryTree", orig.as()))); + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back(std::string("ctfdict") + nm, orig, "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Calib/CTFDictionaryTree", orig.as()))); + } inputs.emplace_back(std::string("trigoffset"), "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ EntropyDecoderSpec::getName(orig), inputs, outputs, - AlgorithmSpec{adaptFromTask(orig, verbosity, getDigits)}, - Options{ - {"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"mask-noise", VariantType::Bool, false, {"apply noise mask to digits or clusters (involves reclusterization)"}}, - {"ignore-cluster-dictionary", VariantType::Bool, false, {"do not use cluster dictionary, always store explicit patterns"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(orig, verbosity, getDigits, ctfdictOpt)}, + Options{{"mask-noise", VariantType::Bool, false, {"apply noise mask to digits or clusters (involves reclusterization)"}}, + {"ignore-cluster-dictionary", VariantType::Bool, false, {"do not use cluster dictionary, always store explicit patterns"}}, + {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace itsmft } // namespace o2 diff --git a/Detectors/ITSMFT/common/workflow/src/EntropyEncoderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/EntropyEncoderSpec.cxx index 4b35f6cc44e39..a824184330547 100644 --- a/Detectors/ITSMFT/common/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/EntropyEncoderSpec.cxx @@ -27,9 +27,8 @@ namespace o2 { namespace itsmft { - -EntropyEncoderSpec::EntropyEncoderSpec(o2::header::DataOrigin orig, bool selIR) - : mOrigin(orig), mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, orig == o2::header::gDataOriginITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(o2::header::DataOrigin orig, bool selIR, const std::string& ctfdictOpt) + : mOrigin(orig), mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, orig == o2::header::gDataOriginITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT, ctfdictOpt), mSelIR(selIR) { assert(orig == o2::header::gDataOriginITS || orig == o2::header::gDataOriginMFT); mTimer.Stop(); @@ -112,7 +111,7 @@ void EntropyEncoderSpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) } } -DataProcessorSpec getEntropyEncoderSpec(o2::header::DataOrigin orig, bool selIR) +DataProcessorSpec getEntropyEncoderSpec(o2::header::DataOrigin orig, bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("compClusters", orig, "COMPCLUSTERS", 0, Lifetime::Timeframe); @@ -123,19 +122,20 @@ DataProcessorSpec getEntropyEncoderSpec(o2::header::DataOrigin orig, bool selIR) inputs.emplace_back("cldict", orig, "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Calib/ClusterDictionary", orig.as()))); inputs.emplace_back("alppar", orig, "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Config/AlpideParam", orig.as()))); } - inputs.emplace_back("ctfdict", orig, "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Calib/CTFDictionaryTree", orig.as()))); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", orig, "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec(fmt::format("{}/Calib/CTFDictionaryTree", orig.as()))); + } return DataProcessorSpec{ orig == o2::header::gDataOriginITS ? "its-entropy-encoder" : "mft-entropy-encoder", inputs, Outputs{{orig, "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, orig, "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(orig, selIR)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(orig, selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace itsmft } // namespace o2 diff --git a/Detectors/ITSMFT/common/workflow/src/entropy-encoder-workflow.cxx b/Detectors/ITSMFT/common/workflow/src/entropy-encoder-workflow.cxx index 6b0585e293db6..5f09fd6c69a97 100644 --- a/Detectors/ITSMFT/common/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/ITSMFT/common/workflow/src/entropy-encoder-workflow.cxx @@ -24,6 +24,7 @@ void customize(std::vector& workflowOptions) std::vector options{ ConfigParamSpec{"runmft", VariantType::Bool, false, {"source detector is MFT (default ITS)"}}, ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -40,7 +41,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); bool selIR = cfgc.options().get("select-ir-frames"); if (cfgc.options().get("runmft")) { - wf.emplace_back(o2::itsmft::getEntropyEncoderSpec("MFT", selIR)); + wf.emplace_back(o2::itsmft::getEntropyEncoderSpec("MFT", selIR, cfgc.options().get("ctf-dict"))); } else { wf.emplace_back(o2::itsmft::getEntropyEncoderSpec("ITS", selIR)); } diff --git a/Detectors/MUON/MCH/CTF/include/MCHCTF/CTFCoder.h b/Detectors/MUON/MCH/CTF/include/MCHCTF/CTFCoder.h index 2d65cbbaea614..5c9da95a98354 100644 --- a/Detectors/MUON/MCH/CTF/include/MCHCTF/CTFCoder.h +++ b/Detectors/MUON/MCH/CTF/include/MCHCTF/CTFCoder.h @@ -37,7 +37,7 @@ namespace mch class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::MCH) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), 1.f, o2::detectors::DetID::MCH, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode data to buffer with CTF diff --git a/Detectors/MUON/MCH/CTF/include/MCHCTF/EntropyDecoderSpec.h b/Detectors/MUON/MCH/CTF/include/MCHCTF/EntropyDecoderSpec.h index f28ca90e9a339..0c3534ff5cdd1 100644 --- a/Detectors/MUON/MCH/CTF/include/MCHCTF/EntropyDecoderSpec.h +++ b/Detectors/MUON/MCH/CTF/include/MCHCTF/EntropyDecoderSpec.h @@ -22,7 +22,7 @@ namespace o2 namespace mch { /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, const char* specName, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, const char* specName, unsigned int sspec, const std::string& ctfdictOpt = "none"); } // namespace mch } // namespace o2 diff --git a/Detectors/MUON/MCH/CTF/src/EntropyDecoderSpec.cxx b/Detectors/MUON/MCH/CTF/src/EntropyDecoderSpec.cxx index 9ec13fed85690..653120bd9b630 100644 --- a/Detectors/MUON/MCH/CTF/src/EntropyDecoderSpec.cxx +++ b/Detectors/MUON/MCH/CTF/src/EntropyDecoderSpec.cxx @@ -27,11 +27,10 @@ namespace o2 { namespace mch { - class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -43,7 +42,7 @@ class EntropyDecoderSpec : public o2::framework::Task TStopwatch mTimer; }; -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); @@ -91,7 +90,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, const char* specName, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, const char* specName, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"rofs"}, "MCH", "DIGITROFS", 0, Lifetime::Timeframe}, @@ -101,17 +100,18 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, const char* specName, uns std::vector inputs; inputs.emplace_back("ctf_MCH", "MCH", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_MCH", "MCH", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("MCH/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_MCH", "MCH", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("MCH/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ specName, inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace mch } // namespace o2 diff --git a/Detectors/MUON/MCH/Workflow/src/entropy-encoder-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/entropy-encoder-workflow.cxx index 058202dfb802b..b5f371edfc759 100644 --- a/Detectors/MUON/MCH/Workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/entropy-encoder-workflow.cxx @@ -27,11 +27,10 @@ namespace o2 { namespace mch { - class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR); + EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -44,7 +43,7 @@ class EntropyEncoderSpec : public o2::framework::Task TStopwatch mTimer; }; -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -85,12 +84,15 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(const char* specName, bool selIR) +DataProcessorSpec getEntropyEncoderSpec(const char* specName, bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("rofs", "MCH", "DIGITROFS", 0, Lifetime::Timeframe); inputs.emplace_back("digits", "MCH", "DIGITS", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "MCH", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("MCH/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "MCH", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("MCH/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -99,14 +101,12 @@ DataProcessorSpec getEntropyEncoderSpec(const char* specName, bool selIR) inputs, Outputs{{"MCH", "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, "MCH", "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace mch } // namespace o2 @@ -118,6 +118,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -133,6 +134,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); bool selIR = cfgc.options().get("select-ir-frames"); - wf.emplace_back(o2::mch::getEntropyEncoderSpec("mch-entropy-encoder", selIR)); + wf.emplace_back(o2::mch::getEntropyEncoderSpec("mch-entropy-encoder", selIR, cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/MUON/MID/CTF/include/MIDCTF/CTFCoder.h b/Detectors/MUON/MID/CTF/include/MIDCTF/CTFCoder.h index 5afc42550ae3e..defec7207f808 100644 --- a/Detectors/MUON/MID/CTF/include/MIDCTF/CTFCoder.h +++ b/Detectors/MUON/MID/CTF/include/MIDCTF/CTFCoder.h @@ -37,7 +37,7 @@ namespace mid class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::MID) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), 1.f, o2::detectors::DetID::MID, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode data to buffer with CTF diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyDecoderSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyDecoderSpec.h index 301db519b9a5f..8f466ac8b7a54 100644 --- a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyDecoderSpec.h +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyDecoderSpec.h @@ -28,7 +28,7 @@ namespace mid class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -41,7 +41,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt); } // namespace mid } // namespace o2 diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyEncoderSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyEncoderSpec.h index e90c96e6ac8fe..20858ca6dfc07 100644 --- a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyEncoderSpec.h +++ b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyEncoderSpec.h @@ -29,7 +29,7 @@ namespace mid class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR); + EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -43,7 +43,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace mid } // namespace o2 diff --git a/Detectors/MUON/MID/Workflow/src/EntropyDecoderSpec.cxx b/Detectors/MUON/MID/Workflow/src/EntropyDecoderSpec.cxx index 5a8df6f8e81cb..0f6dc8bbaa995 100644 --- a/Detectors/MUON/MID/Workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/MUON/MID/Workflow/src/EntropyDecoderSpec.cxx @@ -26,8 +26,7 @@ namespace o2 { namespace mid { - -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); @@ -84,7 +83,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs; for (o2::header::DataHeader::SubSpecificationType subSpec = 0; subSpec < NEvTypes; ++subSpec) { @@ -94,17 +93,18 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) outputs.emplace_back(OutputSpec{{"ctfrep"}, "MID", "CTFDECREP", 0, Lifetime::Timeframe}); std::vector inputs; inputs.emplace_back("ctf_MID", "MID", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_MID", "MID", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("MID/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_MID", "MID", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("MID/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ "mid-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace mid } // namespace o2 diff --git a/Detectors/MUON/MID/Workflow/src/EntropyEncoderSpec.cxx b/Detectors/MUON/MID/Workflow/src/EntropyEncoderSpec.cxx index a472d6e28ff16..d75fe3fa6fbf2 100644 --- a/Detectors/MUON/MID/Workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/MUON/MID/Workflow/src/EntropyEncoderSpec.cxx @@ -32,8 +32,7 @@ namespace o2 { namespace mid { - -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -100,12 +99,15 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("rofs", ConcreteDataTypeMatcher(header::gDataOriginMID, "DATAROF"), Lifetime::Timeframe); inputs.emplace_back("cols", ConcreteDataTypeMatcher(header::gDataOriginMID, "DATA"), Lifetime::Timeframe); - inputs.emplace_back("ctfdict", header::gDataOriginMID, "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("MID/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", header::gDataOriginMID, "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("MID/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -114,13 +116,11 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR) inputs, Outputs{{header::gDataOriginMID, "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, header::gDataOriginMID, "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace mid } // namespace o2 diff --git a/Detectors/MUON/MID/Workflow/src/entropy-encoder-workflow.cxx b/Detectors/MUON/MID/Workflow/src/entropy-encoder-workflow.cxx index 56c482c514e38..25b038190281a 100644 --- a/Detectors/MUON/MID/Workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/MUON/MID/Workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -37,6 +38,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::mid::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"))); + wf.emplace_back(o2::mid::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CTFCoder.h b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CTFCoder.h index 8a7172f634a33..e222328a351c0 100644 --- a/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CTFCoder.h +++ b/Detectors/PHOS/reconstruction/include/PHOSReconstruction/CTFCoder.h @@ -35,7 +35,7 @@ namespace phos class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::PHS) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), 1.f, o2::detectors::DetID::PHS, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode data to buffer with CTF diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/EntropyDecoderSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/EntropyDecoderSpec.h index 1890864af77ea..a6045cf36f7b2 100644 --- a/Detectors/PHOS/workflow/include/PHOSWorkflow/EntropyDecoderSpec.h +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/EntropyDecoderSpec.h @@ -28,7 +28,7 @@ namespace phos class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -41,7 +41,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt); } // namespace phos } // namespace o2 diff --git a/Detectors/PHOS/workflow/include/PHOSWorkflow/EntropyEncoderSpec.h b/Detectors/PHOS/workflow/include/PHOSWorkflow/EntropyEncoderSpec.h index 4ac8240f4c234..c88bddedc7e20 100644 --- a/Detectors/PHOS/workflow/include/PHOSWorkflow/EntropyEncoderSpec.h +++ b/Detectors/PHOS/workflow/include/PHOSWorkflow/EntropyEncoderSpec.h @@ -28,7 +28,7 @@ namespace phos class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR); + EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -42,7 +42,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace phos } // namespace o2 diff --git a/Detectors/PHOS/workflow/src/EntropyDecoderSpec.cxx b/Detectors/PHOS/workflow/src/EntropyDecoderSpec.cxx index a3d15862a2057..20b161b2d2325 100644 --- a/Detectors/PHOS/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/PHOS/workflow/src/EntropyDecoderSpec.cxx @@ -24,8 +24,7 @@ namespace o2 { namespace phos { - -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); @@ -74,7 +73,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"triggers"}, "PHS", "CELLTRIGREC", 0, Lifetime::Timeframe}, @@ -83,17 +82,18 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) std::vector inputs; inputs.emplace_back("ctf_PHS", "PHS", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_PHS", "PHS", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("PHS/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_PHS", "PHS", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("PHS/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ "phos-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace phos } // namespace o2 diff --git a/Detectors/PHOS/workflow/src/EntropyEncoderSpec.cxx b/Detectors/PHOS/workflow/src/EntropyEncoderSpec.cxx index a932a45f1bb53..66a0e04ed3895 100644 --- a/Detectors/PHOS/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/PHOS/workflow/src/EntropyEncoderSpec.cxx @@ -25,8 +25,7 @@ namespace o2 { namespace phos { - -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -70,12 +69,15 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("triggers", "PHS", "CELLTRIGREC", 0, Lifetime::Timeframe); inputs.emplace_back("cells", "PHS", "CELLS", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "PHS", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("PHS/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "PHS", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("PHS/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -84,13 +86,11 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR) inputs, Outputs{{"PHS", "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, "PHS", "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace phos } // namespace o2 diff --git a/Detectors/PHOS/workflow/src/entropy-encoder-workflow.cxx b/Detectors/PHOS/workflow/src/entropy-encoder-workflow.cxx index c7266925060c2..41642cd026089 100644 --- a/Detectors/PHOS/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/PHOS/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -37,6 +38,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::phos::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"))); + wf.emplace_back(o2::phos::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/TOF/reconstruction/include/TOFReconstruction/CTFCoder.h b/Detectors/TOF/reconstruction/include/TOFReconstruction/CTFCoder.h index e7a203cfcb25e..53cdf59d08572 100644 --- a/Detectors/TOF/reconstruction/include/TOFReconstruction/CTFCoder.h +++ b/Detectors/TOF/reconstruction/include/TOFReconstruction/CTFCoder.h @@ -34,7 +34,7 @@ namespace tof class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::TOF) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), 1.f, o2::detectors::DetID::TOF, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode clusters to buffer with CTF diff --git a/Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyDecoderSpec.h b/Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyDecoderSpec.h index c09aa6abc9f7b..714b23d955a78 100644 --- a/Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyDecoderSpec.h +++ b/Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyDecoderSpec.h @@ -29,7 +29,7 @@ namespace tof class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -43,7 +43,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt); } // namespace tof } // namespace o2 diff --git a/Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyEncoderSpec.h b/Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyEncoderSpec.h index ee0739c076597..27377b6447d1c 100644 --- a/Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyEncoderSpec.h +++ b/Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyEncoderSpec.h @@ -29,7 +29,7 @@ namespace tof class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR); + EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -43,7 +43,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace tof } // namespace o2 diff --git a/Detectors/TOF/workflow/src/EntropyDecoderSpec.cxx b/Detectors/TOF/workflow/src/EntropyDecoderSpec.cxx index 400914c64021f..8c0445e3ee3cb 100644 --- a/Detectors/TOF/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/TOF/workflow/src/EntropyDecoderSpec.cxx @@ -25,8 +25,7 @@ namespace o2 { namespace tof { - -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); @@ -93,7 +92,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"digitheader"}, o2::header::gDataOriginTOF, "DIGITHEADER", 0, Lifetime::Timeframe}, @@ -105,17 +104,18 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) std::vector inputs; inputs.emplace_back("ctf_TOF", "TOF", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_TOF", "TOF", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("TOF/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_TOF", "TOF", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("TOF/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ "tof-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace tof } // namespace o2 diff --git a/Detectors/TOF/workflow/src/EntropyEncoderSpec.cxx b/Detectors/TOF/workflow/src/EntropyEncoderSpec.cxx index 3fc47955f53c0..27d7c162cf670 100644 --- a/Detectors/TOF/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/TOF/workflow/src/EntropyEncoderSpec.cxx @@ -25,8 +25,7 @@ namespace o2 { namespace tof { - -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -71,13 +70,16 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("compDigits", o2::header::gDataOriginTOF, "DIGITS", 0, Lifetime::Timeframe); inputs.emplace_back("patterns", o2::header::gDataOriginTOF, "PATTERNS", 0, Lifetime::Timeframe); inputs.emplace_back("ROframes", o2::header::gDataOriginTOF, "READOUTWINDOW", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "TOF", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("TOF/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "TOF", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("TOF/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -86,14 +88,12 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR) inputs, Outputs{{o2::header::gDataOriginTOF, "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, "TOF", "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"irframe-shift", VariantType::Int, o2::tof::Geo::LATENCYWINDOW_IN_BC, {"IRFrame shift to account for latency"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace tof } // namespace o2 diff --git a/Detectors/TOF/workflow/src/entropy-encoder-workflow.cxx b/Detectors/TOF/workflow/src/entropy-encoder-workflow.cxx index 1969672ad3fa3..5cf882e2723d6 100644 --- a/Detectors/TOF/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/TOF/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -37,6 +38,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::tof::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"))); + wf.emplace_back(o2::tof::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/CTFCoder.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/CTFCoder.h index 12d66ef6a6e7c..2c6fac7dcde2a 100644 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/CTFCoder.h +++ b/Detectors/TPC/reconstruction/include/TPCReconstruction/CTFCoder.h @@ -122,7 +122,7 @@ struct MergedColumnsDecoder { class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::TPC) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), 1.f, o2::detectors::DetID::TPC, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode compressed clusters to flat buffer diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/EntropyDecoderSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/EntropyDecoderSpec.h index d36391adfab51..767b68644d698 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/EntropyDecoderSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/EntropyDecoderSpec.h @@ -28,7 +28,7 @@ namespace tpc class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none") : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); @@ -47,7 +47,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt = "none"); } // namespace tpc } // namespace o2 diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/EntropyEncoderSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/EntropyEncoderSpec.h index ac6fafec0a554..1b8483953a8ab 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/EntropyEncoderSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/EntropyEncoderSpec.h @@ -45,7 +45,7 @@ class VDriftHelper; class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool fromFile, bool selIR = false, std::shared_ptr pgg = std::shared_ptr()); + EntropyEncoderSpec(bool fromFile, bool selIR = false, std::shared_ptr pgg = std::shared_ptr(), const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -71,7 +71,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool inputFromFile, bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool inputFromFile, bool selIR = false, const std::string& ctfdictOpt = "none"); } // end namespace tpc } // end namespace o2 diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h b/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h index a5368f451a820..8e8a6a96eed63 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h @@ -85,6 +85,7 @@ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, int caClusterer = 0, // int zsOnTheFly = 0, bool askDISTSTF = true, + const std::string& ctfdictOpt = "none", bool selIR = false, bool filteredInp = false, int deadMapSources = -1, diff --git a/Detectors/TPC/workflow/src/EntropyDecoderSpec.cxx b/Detectors/TPC/workflow/src/EntropyDecoderSpec.cxx index 4ff3573918722..dd73d582553e6 100644 --- a/Detectors/TPC/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/TPC/workflow/src/EntropyDecoderSpec.cxx @@ -26,7 +26,6 @@ namespace o2 { namespace tpc { - void EntropyDecoderSpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) { if (mCTFCoder.finaliseCCDB(matcher, obj)) { @@ -66,11 +65,14 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("ctf_TPC", "TPC", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_TPC", "TPC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("TPC/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_TPC", "TPC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("TPC/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ @@ -79,10 +81,8 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) Outputs{OutputSpec{{"output"}, "TPC", "COMPCLUSTERSFLAT", 0, Lifetime::Timeframe}, OutputSpec{{"trigger"}, "TPC", "TRIGGERWORDS", 0, Lifetime::Timeframe}, OutputSpec{{"ctfrep"}, "TPC", "CTFDECREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace tpc } // namespace o2 diff --git a/Detectors/TPC/workflow/src/EntropyEncoderSpec.cxx b/Detectors/TPC/workflow/src/EntropyEncoderSpec.cxx index 2efa7077be125..73bdfa1905f3b 100644 --- a/Detectors/TPC/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/TPC/workflow/src/EntropyEncoderSpec.cxx @@ -38,10 +38,9 @@ namespace o2 { namespace tpc { - EntropyEncoderSpec::~EntropyEncoderSpec() = default; -EntropyEncoderSpec::EntropyEncoderSpec(bool fromFile, bool selIR, std::shared_ptr pgg) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mFromFile(fromFile), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool fromFile, bool selIR, std::shared_ptr pgg, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mFromFile(fromFile), mSelIR(selIR) { if (mSelIR) { mGRPRequest = pgg; @@ -305,13 +304,16 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool inputFromFile, bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool inputFromFile, bool selIR, const std::string& ctfdictOpt) { std::vector inputs; header::DataDescription inputType = inputFromFile ? header::DataDescription("COMPCLUSTERS") : header::DataDescription("COMPCLUSTERSFLAT"); inputs.emplace_back("input", "TPC", inputType, 0, Lifetime::Timeframe); inputs.emplace_back("trigger", "TPC", "TRIGGERWORDS", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "TPC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("TPC/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "TPC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("TPC/Calib/CTFDictionaryTree")); + } std::shared_ptr ggreq; if (selIR) { @@ -324,9 +326,8 @@ DataProcessorSpec getEntropyEncoderSpec(bool inputFromFile, bool selIR) inputs, Outputs{{"TPC", "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, "TPC", "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(inputFromFile, selIR, ggreq)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"no-ctf-columns-combining", VariantType::Bool, false, {"Do not combine correlated columns in CTF"}}, + AlgorithmSpec{adaptFromTask(inputFromFile, selIR, ggreq, ctfdictOpt)}, + Options{{"no-ctf-columns-combining", VariantType::Bool, false, {"Do not combine correlated columns in CTF"}}, {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"irframe-clusters-maxeta", VariantType::Float, 1.5f, {"Max eta for non-assigned clusters"}}, @@ -335,6 +336,5 @@ DataProcessorSpec getEntropyEncoderSpec(bool inputFromFile, bool selIR) {"nThreads-tpc-encoder", VariantType::UInt32, 1u, {"number of threads to use for decoding"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace tpc } // namespace o2 diff --git a/Detectors/TPC/workflow/src/RecoWorkflow.cxx b/Detectors/TPC/workflow/src/RecoWorkflow.cxx index 98a9841fac8b2..3054dd5d61519 100644 --- a/Detectors/TPC/workflow/src/RecoWorkflow.cxx +++ b/Detectors/TPC/workflow/src/RecoWorkflow.cxx @@ -101,7 +101,7 @@ const std::unordered_map OutputMap{ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vector const& tpcSectors, unsigned long tpcSectorMask, std::vector const& laneConfiguration, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, bool propagateMC, unsigned nLanes, std::string const& cfgInput, std::string const& cfgOutput, bool disableRootInput, - int caClusterer, int zsOnTheFly, bool askDISTSTF, bool selIR, bool filteredInp, int deadMapSources, bool useMCTimeGain) + int caClusterer, int zsOnTheFly, bool askDISTSTF, const std::string& ctfdictOpt, bool selIR, bool filteredInp, int deadMapSources, bool useMCTimeGain) { InputType inputType; try { @@ -507,7 +507,7 @@ framework::WorkflowSpec getWorkflow(CompletionPolicyData* policyData, std::vecto // // selected by output type 'encoded-clusters' if (runClusterEncoder) { - specs.emplace_back(o2::tpc::getEntropyEncoderSpec(!runGPUReco && inputType != InputType::CompClustersFlatForEncode, selIR)); + specs.emplace_back(o2::tpc::getEntropyEncoderSpec(!runGPUReco && inputType != InputType::CompClustersFlatForEncode, selIR, ctfdictOpt)); } ////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Detectors/TPC/workflow/src/entropy-encoder-workflow.cxx b/Detectors/TPC/workflow/src/entropy-encoder-workflow.cxx index 3f9029cf384a9..c09eb193e0fbf 100644 --- a/Detectors/TPC/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/TPC/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}, ConfigParamSpec{"inputFromFile", VariantType::Bool, false, {"Expect COMPCLUSTERS from file"}}}; @@ -38,6 +39,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::tpc::getEntropyEncoderSpec(cfgc.options().get("inputFromFile"), cfgc.options().get("select-ir-frames"))); + wf.emplace_back(o2::tpc::getEntropyEncoderSpec(cfgc.options().get("inputFromFile"), cfgc.options().get("select-ir-frames"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx b/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx index 3c8804de8b536..07b1c293bff98 100644 --- a/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx +++ b/Detectors/TPC/workflow/src/tpc-reco-workflow.cxx @@ -71,6 +71,7 @@ void customize(std::vector& workflowOptions) {"configFile", VariantType::String, "", {"configuration file for configurable parameters"}}, {"filtered-input", VariantType::Bool, false, {"Filtered tracks, clusters input, prefix dataDescriptors with F"}}, {"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}, + {"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, {"tpc-deadMap-sources", VariantType::Int, -1, {"Sources to consider for TPC dead channel map creation; -1=all, 0=deactivated"}}, {"tpc-mc-time-gain", VariantType::Bool, false, {"use time gain calibration for MC (true) or for data (false)"}}, }; @@ -182,6 +183,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) !cfgc.options().get("no-ca-clusterer"), // !cfgc.options().get("no-tpc-zs-on-the-fly"), // !cfgc.options().get("ignore-dist-stf"), // + cfgc.options().get("ctf-dict"), cfgc.options().get("select-ir-frames"), cfgc.options().get("filtered-input"), cfgc.options().get("tpc-deadMap-sources"), diff --git a/Detectors/TRD/reconstruction/include/TRDReconstruction/CTFCoder.h b/Detectors/TRD/reconstruction/include/TRDReconstruction/CTFCoder.h index 9eeaf19db5025..adb584ef15ec4 100644 --- a/Detectors/TRD/reconstruction/include/TRDReconstruction/CTFCoder.h +++ b/Detectors/TRD/reconstruction/include/TRDReconstruction/CTFCoder.h @@ -36,7 +36,7 @@ namespace trd class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::TRD) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), 1.f, o2::detectors::DetID::TRD, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode data to buffer with CTF diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/EntropyDecoderSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/EntropyDecoderSpec.h index 53c591e343134..9521d6262afbf 100644 --- a/Detectors/TRD/workflow/include/TRDWorkflow/EntropyDecoderSpec.h +++ b/Detectors/TRD/workflow/include/TRDWorkflow/EntropyDecoderSpec.h @@ -24,7 +24,7 @@ namespace trd { /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt = "none"); } // namespace trd } // namespace o2 diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/EntropyEncoderSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/EntropyEncoderSpec.h index 673b600bee051..e31a629225f2c 100644 --- a/Detectors/TRD/workflow/include/TRDWorkflow/EntropyEncoderSpec.h +++ b/Detectors/TRD/workflow/include/TRDWorkflow/EntropyEncoderSpec.h @@ -24,7 +24,7 @@ namespace trd { /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace trd } // namespace o2 diff --git a/Detectors/TRD/workflow/src/EntropyDecoderSpec.cxx b/Detectors/TRD/workflow/src/EntropyDecoderSpec.cxx index b30732927c182..2caa4c370a021 100644 --- a/Detectors/TRD/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/TRD/workflow/src/EntropyDecoderSpec.cxx @@ -27,11 +27,10 @@ namespace o2 { namespace trd { - class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -44,7 +43,7 @@ class EntropyDecoderSpec : public o2::framework::Task TStopwatch mTimer; }; -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); @@ -109,7 +108,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"triggers"}, "TRD", "TRKTRGRD", 0, Lifetime::Timeframe}, @@ -119,19 +118,20 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) std::vector inputs; inputs.emplace_back("ctf_TRD", "TRD", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_TRD", "TRD", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_TRD", "TRD", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ "trd-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"correct-trd-trigger-offset", VariantType::Bool, false, {"Correct decoded IR by TriggerOffsetsParam::LM_L0"}}, + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"correct-trd-trigger-offset", VariantType::Bool, false, {"Correct decoded IR by TriggerOffsetsParam::LM_L0"}}, {"bogus-trigger-rejection", VariantType::Int, 10, {">0 : discard, warn N times, <0 : warn only, =0: no check for triggers with no tracklets or bogus IR"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace trd } // namespace o2 diff --git a/Detectors/TRD/workflow/src/EntropyEncoderSpec.cxx b/Detectors/TRD/workflow/src/EntropyEncoderSpec.cxx index d345dd74141ed..18b9a012db2f1 100644 --- a/Detectors/TRD/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/TRD/workflow/src/EntropyEncoderSpec.cxx @@ -27,11 +27,10 @@ namespace o2 { namespace trd { - class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR); + EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -44,7 +43,7 @@ class EntropyEncoderSpec : public o2::framework::Task TStopwatch mTimer; }; -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -92,13 +91,16 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("triggers", "TRD", "TRKTRGRD", 0, Lifetime::Timeframe); inputs.emplace_back("tracklets", "TRD", "TRACKLETS", 0, Lifetime::Timeframe); inputs.emplace_back("digits", "TRD", "DIGITS", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "TRD", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "TRD", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("TRD/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -107,14 +109,12 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR) inputs, Outputs{{"TRD", "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, "TRD", "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"bogus-trigger-check", VariantType::Int, 10, {"max bogus triggers to report, all if < 0"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace trd } // namespace o2 diff --git a/Detectors/TRD/workflow/src/entropy-encoder-workflow.cxx b/Detectors/TRD/workflow/src/entropy-encoder-workflow.cxx index 83fff5bceedef..177f6e4913a26 100644 --- a/Detectors/TRD/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/TRD/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -37,6 +38,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) WorkflowSpec wf; // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::trd::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"))); + wf.emplace_back(o2::trd::getEntropyEncoderSpec(cfgc.options().get("select-ir-frames"), cfgc.options().get("ctf-dict"))); return wf; } diff --git a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFCoder.h b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFCoder.h index f8823e4fc66a5..a299431ef17fc 100644 --- a/Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFCoder.h +++ b/Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFCoder.h @@ -35,7 +35,7 @@ namespace zdc class CTFCoder final : public o2::ctf::CTFCoderBase { public: - CTFCoder(o2::ctf::CTFCoderBase::OpType op) : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), o2::detectors::DetID::ZDC) {} + CTFCoder(o2::ctf::CTFCoderBase::OpType op, const std::string& ctfdictOpt = "none") : o2::ctf::CTFCoderBase(op, CTF::getNBlocks(), 1.f, o2::detectors::DetID::ZDC, ctfdictOpt) {} ~CTFCoder() final = default; /// entropy-encode data to buffer with CTF diff --git a/Detectors/ZDC/workflow/include/ZDCWorkflow/EntropyDecoderSpec.h b/Detectors/ZDC/workflow/include/ZDCWorkflow/EntropyDecoderSpec.h index ae53ca8bdd0fb..6226b4dc99fe3 100644 --- a/Detectors/ZDC/workflow/include/ZDCWorkflow/EntropyDecoderSpec.h +++ b/Detectors/ZDC/workflow/include/ZDCWorkflow/EntropyDecoderSpec.h @@ -28,7 +28,7 @@ namespace zdc class EntropyDecoderSpec : public o2::framework::Task { public: - EntropyDecoderSpec(int verbosity); + EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt = "none"); ~EntropyDecoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -41,7 +41,7 @@ class EntropyDecoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec); +framework::DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt); } // namespace zdc } // namespace o2 diff --git a/Detectors/ZDC/workflow/include/ZDCWorkflow/EntropyEncoderSpec.h b/Detectors/ZDC/workflow/include/ZDCWorkflow/EntropyEncoderSpec.h index 4979de5a30332..44c4585bf0c3f 100644 --- a/Detectors/ZDC/workflow/include/ZDCWorkflow/EntropyEncoderSpec.h +++ b/Detectors/ZDC/workflow/include/ZDCWorkflow/EntropyEncoderSpec.h @@ -29,7 +29,7 @@ namespace zdc class EntropyEncoderSpec : public o2::framework::Task { public: - EntropyEncoderSpec(bool selIR); + EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt = "none"); ~EntropyEncoderSpec() override = default; void run(o2::framework::ProcessingContext& pc) final; void init(o2::framework::InitContext& ic) final; @@ -43,7 +43,7 @@ class EntropyEncoderSpec : public o2::framework::Task }; /// create a processor spec -framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false); +framework::DataProcessorSpec getEntropyEncoderSpec(bool selIR = false, const std::string& ctfdictOpt = "none"); } // namespace zdc } // namespace o2 diff --git a/Detectors/ZDC/workflow/src/EntropyDecoderSpec.cxx b/Detectors/ZDC/workflow/src/EntropyDecoderSpec.cxx index bf870324ce442..59c774662525a 100644 --- a/Detectors/ZDC/workflow/src/EntropyDecoderSpec.cxx +++ b/Detectors/ZDC/workflow/src/EntropyDecoderSpec.cxx @@ -25,8 +25,7 @@ namespace o2 { namespace zdc { - -EntropyDecoderSpec::EntropyDecoderSpec(int verbosity) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder) +EntropyDecoderSpec::EntropyDecoderSpec(int verbosity, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Decoder, ctfdictOpt) { mTimer.Stop(); mTimer.Reset(); @@ -81,7 +80,7 @@ void EntropyDecoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) +DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec, const std::string& ctfdictOpt) { std::vector outputs{ OutputSpec{{"trig"}, "ZDC", "DIGITSBC", 0, Lifetime::Timeframe}, @@ -91,17 +90,18 @@ DataProcessorSpec getEntropyDecoderSpec(int verbosity, unsigned int sspec) std::vector inputs; inputs.emplace_back("ctf_ZDC", "ZDC", "CTFDATA", sspec, Lifetime::Timeframe); - inputs.emplace_back("ctfdict_ZDC", "ZDC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("ZDC/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict_ZDC", "ZDC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("ZDC/Calib/CTFDictionaryTree")); + } inputs.emplace_back("trigoffset", "CTP", "Trig_Offset", 0, Lifetime::Condition, ccdbParamSpec("CTP/Config/TriggerOffsets")); return DataProcessorSpec{ "zdc-entropy-decoder", inputs, outputs, - AlgorithmSpec{adaptFromTask(verbosity)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; + AlgorithmSpec{adaptFromTask(verbosity, ctfdictOpt)}, + Options{{"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace zdc } // namespace o2 diff --git a/Detectors/ZDC/workflow/src/EntropyEncoderSpec.cxx b/Detectors/ZDC/workflow/src/EntropyEncoderSpec.cxx index abbd821fcb749..1a12360645ab2 100644 --- a/Detectors/ZDC/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/ZDC/workflow/src/EntropyEncoderSpec.cxx @@ -27,8 +27,7 @@ namespace o2 { namespace zdc { - -EntropyEncoderSpec::EntropyEncoderSpec(bool selIR) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder), mSelIR(selIR) +EntropyEncoderSpec::EntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) : mCTFCoder(o2::ctf::CTFCoderBase::OpType::Encoder, ctfdictOpt), mSelIR(selIR) { mTimer.Stop(); mTimer.Reset(); @@ -74,13 +73,16 @@ void EntropyEncoderSpec::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getEntropyEncoderSpec(bool selIR) +DataProcessorSpec getEntropyEncoderSpec(bool selIR, const std::string& ctfdictOpt) { std::vector inputs; inputs.emplace_back("trig", "ZDC", "DIGITSBC", 0, Lifetime::Timeframe); inputs.emplace_back("chan", "ZDC", "DIGITSCH", 0, Lifetime::Timeframe); inputs.emplace_back("peds", "ZDC", "DIGITSPD", 0, Lifetime::Timeframe); - inputs.emplace_back("ctfdict", "ZDC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("ZDC/Calib/CTFDictionaryTree")); + + if (ctfdictOpt.empty() || ctfdictOpt == "ccdb") { + inputs.emplace_back("ctfdict", "ZDC", "CTFDICT", 0, Lifetime::Condition, ccdbParamSpec("ZDC/Calib/CTFDictionaryTree")); + } if (selIR) { inputs.emplace_back("selIRFrames", "CTF", "SELIRFRAMES", 0, Lifetime::Timeframe); } @@ -89,13 +91,11 @@ DataProcessorSpec getEntropyEncoderSpec(bool selIR) inputs, Outputs{{"ZDC", "CTFDATA", 0, Lifetime::Timeframe}, {{"ctfrep"}, "ZDC", "CTFENCREP", 0, Lifetime::Timeframe}}, - AlgorithmSpec{adaptFromTask(selIR)}, - Options{{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, - {"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, + AlgorithmSpec{adaptFromTask(selIR, ctfdictOpt)}, + Options{{"irframe-margin-bwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame lower boundary when selection is requested"}}, {"irframe-margin-fwd", VariantType::UInt32, 0u, {"margin in BC to add to the IRFrame upper boundary when selection is requested"}}, {"mem-factor", VariantType::Float, 1.f, {"Memory allocation margin factor"}}, {"ans-version", VariantType::String, {"version of ans entropy coder implementation to use"}}}}; } - } // namespace zdc } // namespace o2 diff --git a/Detectors/ZDC/workflow/src/entropy-encoder-workflow.cxx b/Detectors/ZDC/workflow/src/entropy-encoder-workflow.cxx index 070c65ac9196a..9ab0e10098f43 100644 --- a/Detectors/ZDC/workflow/src/entropy-encoder-workflow.cxx +++ b/Detectors/ZDC/workflow/src/entropy-encoder-workflow.cxx @@ -23,6 +23,7 @@ void customize(std::vector& workflowOptions) // option allowing to set parameters std::vector options{ ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + ConfigParamSpec{"ctf-dict", VariantType::String, "ccdb", {"CTF dictionary: empty or ccdb=CCDB, none=no external dictionary otherwise: local filename"}}, ConfigParamSpec{"select-ir-frames", VariantType::Bool, false, {"Subscribe and filter according to external IR Frames"}}}; std::swap(workflowOptions, options); @@ -38,6 +39,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) // Update the (declared) parameters if changed from the command line o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); bool selIR = cfgc.options().get("select-ir-frames"); - wf.emplace_back(o2::zdc::getEntropyEncoderSpec(selIR)); + wf.emplace_back(o2::zdc::getEntropyEncoderSpec(selIR, cfgc.options().get("ctf-dict"))); return wf; } From d00ca87143fa6617948d44aff6ea98e75b7ba7a9 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Wed, 4 Feb 2026 08:06:11 +0100 Subject: [PATCH 154/234] Revert "ITS: GPU: more memory clearing in processNeighbours" This reverts commit aa3ef3751f282ee477e0636d6bd5697c43103381. Signed-off-by: Felix Schlepper --- .../ITS/tracking/GPU/cuda/TrackingKernels.cu | 84 ++++++------------- 1 file changed, 26 insertions(+), 58 deletions(-) diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu index 50888c676df77..a12237358c8bd 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu @@ -39,7 +39,6 @@ // O2 track model #include "ReconstructionDataFormats/Track.h" #include "DetectorsBase/Propagator.h" -#include "utils/strtag.h" using namespace o2::track; namespace o2::its @@ -1107,19 +1106,11 @@ void processNeighboursHandler(const int startLayer, const int nBlocks, const int nThreads) { - constexpr uint64_t Tag = qStr2Tag("ITS_PNH1"); - - // allocators used auto allocInt = gpu::TypedAllocator(alloc); auto allocCellSeed = gpu::TypedAllocator>(alloc); - // use sync_policy, this part cannot be run async but tell thrust to use the allocator - auto sync_policy = THRUST_NAMESPACE::par(gpu::TypedAllocator(alloc)); - - // put initial computation on Tag1 - alloc->pushTagOnStack(Tag); - - // start processing of cells thrust::device_vector> foundSeedsTable(nCells[startLayer] + 1, 0, allocInt); + auto nosync_policy = THRUST_NAMESPACE::par_nosync(gpu::TypedAllocator(alloc)).on(gpu::Stream::DefaultStream); + gpu::processNeighboursKernel<<>>( startLayer, startLevel, @@ -1138,10 +1129,10 @@ void processNeighboursHandler(const int startLayer, maxChi2ClusterAttachment, propagator, matCorrType); - thrust::exclusive_scan(sync_policy, foundSeedsTable.begin(), foundSeedsTable.end(), foundSeedsTable.begin()); - auto foundSeeds{foundSeedsTable.back()}; - thrust::device_vector> updatedCellId(foundSeeds, 0, allocInt); - thrust::device_vector, gpu::TypedAllocator>> updatedCellSeed(foundSeeds, allocCellSeed); + thrust::exclusive_scan(nosync_policy, foundSeedsTable.begin(), foundSeedsTable.end(), foundSeedsTable.begin()); + + thrust::device_vector> updatedCellId(foundSeedsTable.back(), 0, allocInt); + thrust::device_vector, gpu::TypedAllocator>> updatedCellSeed(foundSeedsTable.back(), allocCellSeed); gpu::processNeighboursKernel<<>>( startLayer, startLevel, @@ -1160,41 +1151,20 @@ void processNeighboursHandler(const int startLayer, maxChi2ClusterAttachment, propagator, matCorrType); + GPUChkErrS(cudaStreamSynchronize(gpu::Stream::DefaultStream)); - // now do inward steps until stop is reached int level = startLevel; - - // Host buffers to break dependency - // FIXME: these should be on our memory resource! - std::vector hostCellId; - std::vector> hostCellSeed; - - // inward loop + thrust::device_vector> lastCellId(allocInt); + thrust::device_vector, gpu::TypedAllocator>> lastCellSeed(allocCellSeed); for (int iLayer{startLayer - 1}; iLayer > 0 && level > 2; --iLayer) { - // copy current results to host - hostCellId.resize(updatedCellId.size()); - hostCellSeed.resize(updatedCellSeed.size()); - thrust::copy(updatedCellId.begin(), updatedCellId.end(), hostCellId.begin()); - thrust::copy(updatedCellSeed.begin(), updatedCellSeed.end(), hostCellSeed.begin()); - - auto lastCellSeedSize{hostCellSeed.size()}; - // but before we clear the memory, and immediately start a new block - alloc->popTagOffStack(Tag); - alloc->pushTagOnStack(Tag); - - // based on the previous step's result create new LUT and zero it - thrust::device_vector>(allocInt).swap(foundSeedsTable); - foundSeedsTable.resize(lastCellSeedSize + 1); - thrust::fill(sync_policy, foundSeedsTable.begin(), foundSeedsTable.end(), 0); - - // recreate lastCell vectors from host - thrust::device_vector> lastCellId(hostCellId.begin(), hostCellId.end(), allocInt); - thrust::device_vector, gpu::TypedAllocator>> lastCellSeed(hostCellSeed.begin(), hostCellSeed.end(), allocCellSeed); - // also create new vectors on new block + lastCellSeed.swap(updatedCellSeed); + lastCellId.swap(updatedCellId); thrust::device_vector, gpu::TypedAllocator>>(allocCellSeed).swap(updatedCellSeed); thrust::device_vector>(allocInt).swap(updatedCellId); + auto lastCellSeedSize{lastCellSeed.size()}; + foundSeedsTable.resize(lastCellSeedSize + 1); + thrust::fill(nosync_policy, foundSeedsTable.begin(), foundSeedsTable.end(), 0); - // start step gpu::processNeighboursKernel<<>>( iLayer, --level, @@ -1213,13 +1183,14 @@ void processNeighboursHandler(const int startLayer, maxChi2ClusterAttachment, propagator, matCorrType); - // how many new seeds where found - thrust::exclusive_scan(sync_policy, foundSeedsTable.begin(), foundSeedsTable.end(), foundSeedsTable.begin()); - foundSeeds = foundSeedsTable.back(); - // do a resize, we don't need to set the memory now since we know that all of these are written to - // Note though this does not clear the memory... + thrust::exclusive_scan(nosync_policy, foundSeedsTable.begin(), foundSeedsTable.end(), foundSeedsTable.begin()); + + auto foundSeeds{foundSeedsTable.back()}; updatedCellId.resize(foundSeeds); + thrust::fill(nosync_policy, updatedCellId.begin(), updatedCellId.end(), 0); updatedCellSeed.resize(foundSeeds); + thrust::fill(nosync_policy, updatedCellSeed.begin(), updatedCellSeed.end(), CellSeed()); + gpu::processNeighboursKernel<<>>( iLayer, level, @@ -1239,15 +1210,12 @@ void processNeighboursHandler(const int startLayer, propagator, matCorrType); } - - // final copy of result - const auto selector = gpu::seed_selector(1.e3, maxChi2NDF * ((startLevel + 2) * 2 - 5)); - const auto count = thrust::count_if(sync_policy, updatedCellSeed.begin(), updatedCellSeed.end(), selector); - thrust::device_vector, gpu::TypedAllocator>> outSeeds(count, allocCellSeed); - thrust::copy_if(sync_policy, updatedCellSeed.begin(), updatedCellSeed.end(), outSeeds.begin(), selector); - seedsHost.reserve(seedsHost.size() + count); - thrust::copy(outSeeds.begin(), outSeeds.end(), std::back_inserter(seedsHost)); - alloc->popTagOffStack(Tag); + GPUChkErrS(cudaStreamSynchronize(gpu::Stream::DefaultStream)); + thrust::device_vector, gpu::TypedAllocator>> outSeeds(updatedCellSeed.size(), allocCellSeed); + auto end = thrust::copy_if(nosync_policy, updatedCellSeed.begin(), updatedCellSeed.end(), outSeeds.begin(), gpu::seed_selector(1.e3, maxChi2NDF * ((startLevel + 2) * 2 - 5))); + auto s{end - outSeeds.begin()}; + seedsHost.reserve(seedsHost.size() + s); + thrust::copy(outSeeds.begin(), outSeeds.begin() + s, std::back_inserter(seedsHost)); } template From 19803f64dccc492a0bfd8d528ea481dcc972faf8 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Thu, 5 Feb 2026 17:44:10 +0100 Subject: [PATCH 155/234] ITS: GPU: add minimal version of clearing Signed-off-by: Felix Schlepper --- Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu index a12237358c8bd..eacf514c7a91d 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu @@ -32,9 +32,9 @@ #include "ITStracking/Cluster.h" #include "ITStracking/Cell.h" #include "DataFormatsITS/TrackITS.h" - #include "ITStrackingGPU/TrackingKernels.h" #include "ITStrackingGPU/Utils.h" +#include "utils/strtag.h" // O2 track model #include "ReconstructionDataFormats/Track.h" @@ -1106,6 +1106,8 @@ void processNeighboursHandler(const int startLayer, const int nBlocks, const int nThreads) { + constexpr uint64_t Tag = qStr2Tag("ITS_PNH1"); + alloc->pushTagOnStack(Tag); auto allocInt = gpu::TypedAllocator(alloc); auto allocCellSeed = gpu::TypedAllocator>(alloc); thrust::device_vector> foundSeedsTable(nCells[startLayer] + 1, 0, allocInt); @@ -1216,6 +1218,7 @@ void processNeighboursHandler(const int startLayer, auto s{end - outSeeds.begin()}; seedsHost.reserve(seedsHost.size() + s); thrust::copy(outSeeds.begin(), outSeeds.begin() + s, std::back_inserter(seedsHost)); + alloc->popTagOffStack(Tag); } template From 5639312fdb8f49ef5365f32985bf9a53187add07 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 5 Feb 2026 21:27:14 +0100 Subject: [PATCH 156/234] GPU CMake: Avoid repetitive JSON parsing --- GPU/GPUTracking/CMakeLists.txt | 6 ++-- .../Definitions/Parameters/GPUParameters.json | 1 - .../cmake/gpu_param_header_generator.cmake | 31 +++++++++++++------ 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index 816d578fb31a3..adfb79a78b994 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -410,12 +410,12 @@ target_sources(${targetName} BASE_DIRS ${CMAKE_CURRENT_BINARY_DIR}) make_directory(${CMAKE_CURRENT_BINARY_DIR}/genGPUArch) -set(GPU_CONST_PARAM_ARCHITECTUES AMPERE TURING VEGA MI100) +set(GPU_CONST_PARAM_ARCHITECTUES "AMPERE;TURING;VEGA;MI100") set(GPU_CONST_PARAM_FILES "") +set(GPU_ARCH_PARAMS_HEADER ${CMAKE_CURRENT_BINARY_DIR}/genGPUArch/GPUDefParametersDefaults_OnTheFly.h) +generate_gpu_param_header("${GPU_CONST_PARAM_ARCHITECTUES}" ${GPU_ARCH_PARAMS_HEADER}) foreach(GPU_ARCH ${GPU_CONST_PARAM_ARCHITECTUES}) set(PARAMFILE ${CMAKE_CURRENT_BINARY_DIR}/genGPUArch/gpu_const_param_${GPU_ARCH}.par) - set(GPU_ARCH_PARAMS_HEADER ${CMAKE_CURRENT_BINARY_DIR}/genGPUArch/GPUDefParametersDefaults_${GPU_ARCH}.h) - generate_gpu_param_header(${GPU_ARCH} ${GPU_ARCH_PARAMS_HEADER}) add_custom_command( OUTPUT ${PARAMFILE} COMMAND bash -c diff --git a/GPU/GPUTracking/Definitions/Parameters/GPUParameters.json b/GPU/GPUTracking/Definitions/Parameters/GPUParameters.json index 285919559c04c..3c6f1af1aab2f 100644 --- a/GPU/GPUTracking/Definitions/Parameters/GPUParameters.json +++ b/GPU/GPUTracking/Definitions/Parameters/GPUParameters.json @@ -2,7 +2,6 @@ "CORE": { "WARP_SIZE": { "default": 32, - "default_cpu": 1, "MI100": 64, "VEGA": 64, "TAHITI": 32, diff --git a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake index 3770e30f2583c..526303a353106 100644 --- a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake +++ b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake @@ -12,7 +12,10 @@ # file gpu_param_header_generator.cmake # author Gabriele Cimador -function(generate_macros json_content header types arch_key use_ifndef_guard) +function(generate_macros json_content output types arch_list) + foreach(arch IN LISTS arch_list) + set(${output}_${arch} "") + endforeach() foreach(TYPE IN LISTS types) string(JSON n_params LENGTH "${json_content}" "${TYPE}") math(EXPR last "${n_params} - 1") @@ -22,8 +25,12 @@ function(generate_macros json_content header types arch_key use_ifndef_guard) math(EXPR last_arch "${n_archs} - 1") foreach(iArch RANGE 0 ${last_arch}) string(JSON arch MEMBER "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${iArch}") - if(arch STREQUAL "${arch_key}") - string(JSON param_values GET "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${arch_key}") + if(arch STREQUAL "default_cpu" AND NOT TYPE STREQUAL "PAR") + message(FATAL_ERROR "Bogus entry ${param_name} for ${arch}") + endif() + list(FIND arch_list "${arch}" list_idx) + if(list_idx GREATER -1) + string(JSON param_values GET "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${arch}") if(TYPE STREQUAL "LB") set(MACRO_NAME "GPUCA_LB_${param_name}") elseif(TYPE STREQUAL "PAR") @@ -36,16 +43,19 @@ function(generate_macros json_content header types arch_key use_ifndef_guard) string(REGEX REPLACE " *\\]$" "" vals "${vals}") string(REGEX REPLACE "\"" "" vals "${vals}") set(MACRO_DEFINITION "#define ${MACRO_NAME} ${vals}") - if(use_ifndef_guard) + if(arch MATCHES ^default) # fallback defaults are wrapped in #ifndef - file(APPEND "${header}" "#ifndef ${MACRO_NAME}\n ${MACRO_DEFINITION}\n#endif\n\n") + string(APPEND ${output}_${arch} "#ifndef ${MACRO_NAME}\n ${MACRO_DEFINITION}\n#endif\n\n") else() - file(APPEND "${header}" "${MACRO_DEFINITION}\n") + string(APPEND ${output}_${arch} "${MACRO_DEFINITION}\n") endif() endif() endforeach() endforeach() endforeach() + foreach(arch IN LISTS arch_list) + set(${output}_${arch} "${${output}_${arch}}" PARENT_SCOPE) + endforeach() endfunction() function(generate_gpu_param_header GPU_ARCH OUT_HEADER) @@ -68,6 +78,7 @@ function(generate_gpu_param_header GPU_ARCH OUT_HEADER) set(TYPES CORE LB PAR) # Per architecture definitions set(_first TRUE) + generate_macros("${JSON_CONTENT}" TMP_OUTPUT "${TYPES}" "${ARCH_LIST};default;default_cpu") foreach(ARCH IN LISTS ARCH_LIST) if(_first) file(APPEND "${TMP_HEADER}" "#if defined(GPUCA_GPUTYPE_${ARCH})\n\n") @@ -75,7 +86,7 @@ function(generate_gpu_param_header GPU_ARCH OUT_HEADER) else() file(APPEND "${TMP_HEADER}" "#elif defined(GPUCA_GPUTYPE_${ARCH})\n\n") endif() - generate_macros("${JSON_CONTENT}" "${TMP_HEADER}" "${TYPES}" "${ARCH}" "") + file(APPEND "${TMP_HEADER}" ${TMP_OUTPUT_${ARCH}}) endforeach() if(NOT _first) file(APPEND "${TMP_HEADER}" "#else\n#error GPU TYPE NOT SET\n#endif\n") @@ -83,16 +94,16 @@ function(generate_gpu_param_header GPU_ARCH OUT_HEADER) # Default parameters file(APPEND "${TMP_HEADER}" "\n// Default parameters if not defined for the target architecture\n\n") - generate_macros("${JSON_CONTENT}" "${TMP_HEADER}" "${TYPES}" "default" "use_ifndef_guard") + file(APPEND "${TMP_HEADER}" ${TMP_OUTPUT_default}) file(APPEND "${TMP_HEADER}" "#endif // defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_NO_LAUNCH_BOUNDS)\n\n") # CPU fallback file(APPEND "${TMP_HEADER}" "#ifndef GPUCA_GPUCODE_GENRTC //Defaults for non-LB parameters also for CPU fallback\n\n") - generate_macros("${JSON_CONTENT}" "${TMP_HEADER}" "PAR" "default_cpu" "use_ifndef_guard") + file(APPEND "${TMP_HEADER}" ${TMP_OUTPUT_default_cpu}) file(APPEND "${TMP_HEADER}" "\n#endif // GPUCA_GPUCODE_GENRTC\n") file(APPEND "${TMP_HEADER}" "\n#endif // GPUDEFPARAMETERSDEFAULTS_H\n") file(RENAME "${TMP_HEADER}" "${OUT_HEADER}") message(STATUS "Generated ${OUT_HEADER}") add_custom_target(GPU_PARAM_HEADER_${GPU_ARCH}_ALL ALL DEPENDS ${OUT_HEADER} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/gpu_param_header_generator.cmake ${GPU_PARAM_JSON}) -endfunction() \ No newline at end of file +endfunction() From e7b5a26d2ad81644dc692c3b740d3124f49d71b0 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 5 Feb 2026 22:06:35 +0100 Subject: [PATCH 157/234] GPU CMake: Generate optimized parameter files for all available architectures, not only for hardcoded list --- GPU/GPUTracking/CMakeLists.txt | 3 +- .../cmake/gpu_param_header_generator.cmake | 37 +++++++++++++++---- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index adfb79a78b994..9f349d0e21f4f 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -410,10 +410,9 @@ target_sources(${targetName} BASE_DIRS ${CMAKE_CURRENT_BINARY_DIR}) make_directory(${CMAKE_CURRENT_BINARY_DIR}/genGPUArch) -set(GPU_CONST_PARAM_ARCHITECTUES "AMPERE;TURING;VEGA;MI100") set(GPU_CONST_PARAM_FILES "") set(GPU_ARCH_PARAMS_HEADER ${CMAKE_CURRENT_BINARY_DIR}/genGPUArch/GPUDefParametersDefaults_OnTheFly.h) -generate_gpu_param_header("${GPU_CONST_PARAM_ARCHITECTUES}" ${GPU_ARCH_PARAMS_HEADER}) +generate_gpu_param_header("ALL" ${GPU_ARCH_PARAMS_HEADER} "GPU_CONST_PARAM_ARCHITECTUES") foreach(GPU_ARCH ${GPU_CONST_PARAM_ARCHITECTUES}) set(PARAMFILE ${CMAKE_CURRENT_BINARY_DIR}/genGPUArch/gpu_const_param_${GPU_ARCH}.par) add_custom_command( diff --git a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake index 526303a353106..0c3e905a697c0 100644 --- a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake +++ b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake @@ -12,10 +12,12 @@ # file gpu_param_header_generator.cmake # author Gabriele Cimador -function(generate_macros json_content output types arch_list) +function(generate_macros json_content output types arch_list arch_list_output) foreach(arch IN LISTS arch_list) - set(${output}_${arch} "") + set(OUTPUT_TMP_${arch} "") endforeach() + set(arch_list_output_tmp) + list(FIND arch_list "ALL" do_all_architectures) foreach(TYPE IN LISTS types) string(JSON n_params LENGTH "${json_content}" "${TYPE}") math(EXPR last "${n_params} - 1") @@ -28,7 +30,14 @@ function(generate_macros json_content output types arch_list) if(arch STREQUAL "default_cpu" AND NOT TYPE STREQUAL "PAR") message(FATAL_ERROR "Bogus entry ${param_name} for ${arch}") endif() - list(FIND arch_list "${arch}" list_idx) + if(do_all_architectures GREATER -1) + if(arch_list_output AND NOT arch MATCHES ^default) + list(APPEND arch_list_output_tmp "${arch}") + endif() + set(list_idx 0) + else() + list(FIND arch_list "${arch}" list_idx) + endif() if(list_idx GREATER -1) string(JSON param_values GET "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${arch}") if(TYPE STREQUAL "LB") @@ -45,17 +54,22 @@ function(generate_macros json_content output types arch_list) set(MACRO_DEFINITION "#define ${MACRO_NAME} ${vals}") if(arch MATCHES ^default) # fallback defaults are wrapped in #ifndef - string(APPEND ${output}_${arch} "#ifndef ${MACRO_NAME}\n ${MACRO_DEFINITION}\n#endif\n\n") + string(APPEND OUTPUT_TMP_${arch} "#ifndef ${MACRO_NAME}\n ${MACRO_DEFINITION}\n#endif\n\n") else() - string(APPEND ${output}_${arch} "${MACRO_DEFINITION}\n") + string(APPEND OUTPUT_TMP_${arch} "${MACRO_DEFINITION}\n") endif() endif() endforeach() endforeach() endforeach() foreach(arch IN LISTS arch_list) - set(${output}_${arch} "${${output}_${arch}}" PARENT_SCOPE) + set(${output}_${arch} "${OUTPUT_TMP_${arch}}" PARENT_SCOPE) endforeach() + if(arch_list_output) + list(REMOVE_DUPLICATES arch_list_output_tmp) + list(SORT arch_list_output_tmp) + set(${arch_list_output} "${arch_list_output_tmp}" PARENT_SCOPE) + endif() endfunction() function(generate_gpu_param_header GPU_ARCH OUT_HEADER) @@ -78,7 +92,14 @@ function(generate_gpu_param_header GPU_ARCH OUT_HEADER) set(TYPES CORE LB PAR) # Per architecture definitions set(_first TRUE) - generate_macros("${JSON_CONTENT}" TMP_OUTPUT "${TYPES}" "${ARCH_LIST};default;default_cpu") + generate_macros("${JSON_CONTENT}" TMP_OUTPUT "${TYPES}" "${ARCH_LIST};default;default_cpu" "JSON_ARCHITECTURES") + list(FIND ARCH_LIST "ALL" do_all_architectures) + if(ARGC GREATER 2) + set(${ARGV2} "${JSON_ARCHITECTURES}" PARENT_SCOPE) + endif() + if(do_all_architectures GREATER -1) + set(ARCH_LIST ${JSON_ARCHITECTURES}) + endif() foreach(ARCH IN LISTS ARCH_LIST) if(_first) file(APPEND "${TMP_HEADER}" "#if defined(GPUCA_GPUTYPE_${ARCH})\n\n") @@ -98,7 +119,7 @@ function(generate_gpu_param_header GPU_ARCH OUT_HEADER) file(APPEND "${TMP_HEADER}" "#endif // defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_NO_LAUNCH_BOUNDS)\n\n") # CPU fallback - file(APPEND "${TMP_HEADER}" "#ifndef GPUCA_GPUCODE_GENRTC //Defaults for non-LB parameters also for CPU fallback\n\n") + file(APPEND "${TMP_HEADER}" "#ifndef GPUCA_GPUCODE_GENRTC // Defaults for non-LB parameters also for CPU fallback\n\n") file(APPEND "${TMP_HEADER}" ${TMP_OUTPUT_default_cpu}) file(APPEND "${TMP_HEADER}" "\n#endif // GPUCA_GPUCODE_GENRTC\n") From 0f4e3152fb0fe97fd29acffbc7954937cf82e381 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 5 Feb 2026 22:36:28 +0100 Subject: [PATCH 158/234] GPU CMake: Make source for GPU parameters configurable, auto-convert CSV to JSON if necessary --- GPU/GPUTracking/CMakeLists.txt | 17 +++ .../Definitions/Parameters/GPUParameters.csv | 113 ++++++++++++++++++ ...meters.json => GPUParameters.json.example} | 0 GPU/GPUTracking/Standalone/cmake/config.cmake | 1 + .../cmake/gpu_param_header_generator.cmake | 1 - 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 GPU/GPUTracking/Definitions/Parameters/GPUParameters.csv rename GPU/GPUTracking/Definitions/Parameters/{GPUParameters.json => GPUParameters.json.example} (100%) diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index 9f349d0e21f4f..cd17d8f284b13 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -107,6 +107,23 @@ set(SRCS_NO_H SectorTracker/GPUTPCTrackerDump.cxx Global/GPUChainTrackingDebugAndProfiling.cxx Global/GPUChainTrackingIO.cxx) +if(GPUCA_OVERRIDE_PARAMETER_FILE) + set(GPU_PARAM_JSON ${GPUCA_OVERRIDE_PARAMETER_FILE}) +else() + set(GPU_PARAM_JSON ${CMAKE_CURRENT_SOURCE_DIR}/Definitions/Parameters/GPUParameters.csv) +endif() +get_filename_component(GPU_PARAM_JSON_EXT ${GPU_PARAM_JSON} EXT) +string(TOLOWER "${GPU_PARAM_JSON_EXT}" GPU_PARAM_JSON_EXT) +if(GPU_PARAM_JSON_EXT STREQUAL .csv) + execute_process( + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/Definitions/Parameters/csv_to_json.sh "${GPU_PARAM_JSON}" + OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/gpu_parameters.json + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + message(STATUS "Converted ${GPU_PARAM_JSON} to ${CMAKE_CURRENT_BINARY_DIR}/gpu_parameters.json") + set(GPU_PARAM_JSON ${CMAKE_CURRENT_BINARY_DIR}/gpu_parameters.json) +endif() + set(ON_THE_FLY_DIR ${CMAKE_CURRENT_BINARY_DIR}/include_gpu_onthefly) file(MAKE_DIRECTORY ${ON_THE_FLY_DIR}) include(cmake/gpu_param_header_generator.cmake) diff --git a/GPU/GPUTracking/Definitions/Parameters/GPUParameters.csv b/GPU/GPUTracking/Definitions/Parameters/GPUParameters.csv new file mode 100644 index 0000000000000..5afa99554f5d0 --- /dev/null +++ b/GPU/GPUTracking/Definitions/Parameters/GPUParameters.csv @@ -0,0 +1,113 @@ +Architecture,default,MI100,VEGA,TAHITI,TESLA,FERMI,PASCAL,KEPLER,AMPERE,TURING,default_cpu +,,,,,,,,,,, +CORE:,,,,,,,,,,, +WARP_SIZE,32,64,64,32,32,32,32,32,32,32, +THREAD_COUNT_DEFAULT,256,256,256,,,,,,512,512, +,,,,,,,,,,, +LB:,,,,,,,,,,, +GPUTPCCreateTrackingData,256,"[256, 7]","[192, 2]",,,,,,384,256, +GPUTPCTrackletConstructor,256,"[768, 8]","[512, 10]","[256, 2]","[256, 1]","[256, 2]","[1024, 2]","[512, 4]","[256, 2]","[256, 2]", +GPUTPCTrackletSelector,256,"[384, 5]","[192, 10]","[256, 3]","[256, 1]","[256, 3]","[512, 4]","[256, 3]","[192, 3]","[192, 3]", +GPUTPCNeighboursFinder,256,"[192, 8]","[960, 8]",256,256,256,512,256,"[640, 1]","[640, 1]", +GPUTPCNeighboursCleaner,256,"[128, 5]","[384, 9]",256,256,256,256,256,512,512, +GPUTPCExtrapolationTracking,256,"[256, 7]","[256, 2]",,,,,,"[128, 4]","[192, 2]", +GPUTRDTrackerKernels_gpuVersion,512,,,,,,,,,, +GPUTPCCreateOccupancyMap_fill,256,,,,,,,,,, +GPUTPCCreateOccupancyMap_fold,256,,,,,,,,,, +GPUTRDTrackerKernels_o2Version,512,,,,,,,,,, +GPUTPCCompressionKernels_step0attached,256,"[128, 1]","[64, 2]",,,,,,"[64, 2]",128, +GPUTPCCompressionKernels_step1unattached,256,"[512, 2]","[512, 2]",,,,,,"[512, 3]","[512, 2]", +GPUTPCDecompressionKernels_step0attached,256,"[128, 2]","[128, 2]",,,,,,"[32, 1]","[32, 1]", +GPUTPCDecompressionKernels_step1unattached,256,"[64, 2]","[64, 2]",,,,,,"[32, 1]","[32, 1]", +GPUTPCDecompressionUtilKernels_sortPerSectorRow,256,,,,,,,,,, +GPUTPCDecompressionUtilKernels_countFilteredClusters,256,,,,,,,,,, +GPUTPCDecompressionUtilKernels_storeFilteredClusters,256,,,,,,,,,, +GPUTPCCFDecodeZS,"[128, 4]","[64, 4]","[64, 1]",,,,,,"[64, 10]","[64, 8]", +GPUTPCCFDecodeZSLink,"""GPUCA_WARP_SIZE""","""GPUCA_WARP_SIZE""","""GPUCA_WARP_SIZE""",,,,,,"""GPUCA_WARP_SIZE""","""GPUCA_WARP_SIZE""", +GPUTPCCFDecodeZSDenseLink,"""GPUCA_WARP_SIZE""","[""GPUCA_WARP_SIZE"", 4]","[""GPUCA_WARP_SIZE"", 14]",,,,,,"""GPUCA_WARP_SIZE""","""GPUCA_WARP_SIZE""", +GPUTPCCFGather,"[1024, 1]","[1024, 5]","[1024, 1]",,,,,,"[1024, 1]","[1024, 1]", +COMPRESSION_GATHER,1024,1024,1024,,,,,,1024,1024, +GPUTPCGMMergerTrackFit,256,"[192, 2]","[64, 7]",,,,,,"[64, 4]","[32, 8]", +GPUTPCGMMergerFollowLoopers,256,"[256, 5]","[256, 4]",,,,,,"[64, 12]","[128, 4]", +GPUTPCGMMergerSectorRefit,256,"[64, 4]","[256, 2]",,,,,,"[32, 6]","[64, 5]", +GPUTPCGMMergerUnpackResetIds,256,256,256,,,,,,256,256, +GPUTPCGMMergerUnpackGlobal,256,256,256,,,,,,256,256, +GPUTPCGMMergerResolve_step0,256,512,256,,,,,,256,256, +GPUTPCGMMergerResolve_step1,256,512,256,,,,,,256,256, +GPUTPCGMMergerResolve_step2,256,512,256,,,,,,256,256, +GPUTPCGMMergerResolve_step3,256,512,256,,,,,,256,256, +GPUTPCGMMergerResolve_step4,256,512,256,,,,,,"[256, 4]","[256, 4]", +GPUTPCGMMergerClearLinks,256,256,256,,,,,,256,256, +GPUTPCGMMergerMergeWithinPrepare,256,256,256,,,,,,256,256, +GPUTPCGMMergerMergeSectorsPrepare,256,256,256,,,,,,"[256, 2]","[256, 2]", +GPUTPCGMMergerMergeBorders_step0,256,512,256,,,,,,192,192, +GPUTPCGMMergerMergeBorders_step2,256,512,256,,,,,,"[64, 2]",256, +GPUTPCGMMergerMergeCE,256,512,256,,,,,,256,256, +GPUTPCGMMergerLinkExtrapolatedTracks,256,256,256,,,,,,256,256, +GPUTPCGMMergerCollect,256,"[768, 1]","[1024, 1]",,,,,,"[256, 2]","[128, 2]", +GPUTPCGMMergerSortTracksPrepare,256,256,256,,,,,,256,256, +GPUTPCGMMergerPrepareForFit_step0,256,256,256,,,,,,256,256, +GPUTPCGMMergerPrepareForFit_step1,256,256,256,,,,,,256,256, +GPUTPCGMMergerPrepareForFit_step2,256,256,256,,,,,,256,256, +GPUTPCGMMergerFinalize_step0,256,,256,,,,,,,, +GPUTPCGMMergerFinalize_step1,256,,256,,,,,,,, +GPUTPCGMMergerFinalize_step2,256,,256,,,,,,,, +GPUTPCGMMergerMergeLoopers_step0,256,,,,,,,,,, +GPUTPCGMMergerMergeLoopers_step1,256,,,,,,,,,, +GPUTPCGMMergerMergeLoopers_step2,256,,,,,,,,,, +GPUTPCGMO2Output_prepare,256,,,,,,,,,, +GPUTPCGMO2Output_output,256,,,,,,,,,, +GPUTPCStartHitsFinder,256,"[1024, 2]","[1024, 7]",256,256,256,256,256,512,512, +GPUTPCStartHitsSorter,256,"[1024, 5]","[512, 7]",256,256,256,256,256,"[512, 1]","[512, 1]", +GPUTPCCFCheckPadBaseline,576,"[576, 2]","[576, 2]",,,,,,"[576, 2]",, +GPUTPCCFChargeMapFiller_fillIndexMap,512,512,512,,,,,,448,, +GPUTPCCFChargeMapFiller_fillFromDigits,512,512,512,,,,,,448,, +GPUTPCCFChargeMapFiller_findFragmentStart,512,512,512,,,,,,448,, +GPUTPCCFPeakFinder,512,"[512, 9]","[512, 4]",,,,,,128,, +GPUTPCCFNoiseSuppression,512,512,512,,,,,,448,, +GPUTPCCFDeconvolution,512,"[512, 5]","[512, 5]",,,,,,384,, +GPUTPCCFClusterizer,512,"[448, 3]","[512, 2]",,,,,,448,, +GPUTPCNNClusterizerKernels,512,,,,,,,,,, +GPUTrackingRefitKernel_mode0asGPU,256,,,,,,,,,, +GPUTrackingRefitKernel_mode1asTrackParCov,256,,,,,,,,,, +GPUMemClean16,"[""GPUCA_THREAD_COUNT_DEFAULT"", 1]",,,,,,,,,, +GPUitoa,"[""GPUCA_THREAD_COUNT_DEFAULT"", 1]",,,,,,,,,, +GPUTPCCFNoiseSuppression_noiseSuppression,"""GPUCA_LB_GPUTPCCFNoiseSuppression""",,,,,,,,,, +GPUTPCCFNoiseSuppression_updatePeaks,"""GPUCA_LB_GPUTPCCFNoiseSuppression""",,,,,,,,,, +GPUTPCNNClusterizerKernels_runCfClusterizer,"""GPUCA_LB_GPUTPCNNClusterizerKernels""",,,,,,,,,, +GPUTPCNNClusterizerKernels_fillInputNNCPU,"""GPUCA_LB_GPUTPCNNClusterizerKernels""",,,,,,,,,, +GPUTPCNNClusterizerKernels_fillInputNNGPU,1024,,,,,,,,,, +GPUTPCNNClusterizerKernels_determineClass1Labels,"""GPUCA_LB_GPUTPCNNClusterizerKernels""",,,,,,,,,, +GPUTPCNNClusterizerKernels_determineClass2Labels,"""GPUCA_LB_GPUTPCNNClusterizerKernels""",,,,,,,,,, +GPUTPCNNClusterizerKernels_publishClass1Regression,"""GPUCA_LB_GPUTPCNNClusterizerKernels""",,,,,,,,,, +GPUTPCNNClusterizerKernels_publishClass2Regression,"""GPUCA_LB_GPUTPCNNClusterizerKernels""",,,,,,,,,, +GPUTPCNNClusterizerKernels_publishDeconvolutionFlags,"""GPUCA_LB_GPUTPCNNClusterizerKernels""",,,,,,,,,, +GPUTPCCFStreamCompaction_scanStart,"""GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE""",,,,,,,,,, +GPUTPCCFStreamCompaction_scanUp,"""GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE""",,,,,,,,,, +GPUTPCCFStreamCompaction_scanTop,"""GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE""",,,,,,,,,, +GPUTPCCFStreamCompaction_scanDown,"""GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE""",,,,,,,,,, +GPUTPCCFStreamCompaction_compactDigits,"""GPUCA_PAR_CF_SCAN_WORKGROUP_SIZE""",,,,,,,,,, +GPUTPCCompressionGatherKernels_unbuffered,"""GPUCA_LB_COMPRESSION_GATHER""",,,,,,,,,, +GPUTPCCompressionGatherKernels_buffered32,"""GPUCA_LB_COMPRESSION_GATHER""",,,,,,,,,, +GPUTPCCompressionGatherKernels_buffered64,"""GPUCA_LB_COMPRESSION_GATHER""",,,,,,,,,, +GPUTPCCompressionGatherKernels_buffered128,"""GPUCA_LB_COMPRESSION_GATHER""",,,,,,,,,, +GPUTPCCompressionGatherKernels_multiBlock,"""GPUCA_LB_COMPRESSION_GATHER""",,,,,,,,,, +GPUTPCGMMergerFinalize_0,256,256,,,,,,,256,256, +GPUTPCGMMergerFinalize_1,256,256,,,,,,,256,256, +GPUTPCGMMergerFinalize_2,256,256,,,,,,,256,256, +,,,,,,,,,,, +PAR:,,,,,,,,,,, +AMD_EUS_PER_CU,0,4,4,,,,,,,,0 +SORT_STARTHITS,1,,,,,,,,,,0 +NEIGHBOURS_FINDER_MAX_NNEIGHUP,6,10,4,,,,,,4,4,0 +NEIGHBOURS_FINDER_UNROLL_GLOBAL,4,4,2,,,,,,,,0 +NEIGHBOURS_FINDER_UNROLL_SHARED,1,0,0,,,,,,,,0 +TRACKLET_SELECTOR_HITS_REG_SIZE,12,9,27,,,,,,20,20,0 +ALTERNATE_BORDER_SORT,0,1,1,,,,,,1,1,0 +SORT_BEFORE_FIT,0,1,1,,,,,,1,1,0 +NO_ATOMIC_PRECHECK,0,1,1,,,,,,1,1,0 +DEDX_STORAGE_TYPE,"""float""","""uint16_t""","""uint16_t""",,,,,,"""uint16_t""","""uint16_t""","""float""" +MERGER_INTERPOLATION_ERROR_TYPE,"""float""","""half""","""half""",,,,,,"""half""","""half""","""float""" +COMP_GATHER_KERNEL,0,4,4,,,,,,4,4,0 +COMP_GATHER_MODE,2,3,3,,,,,,3,3,0 +CF_SCAN_WORKGROUP_SIZE,512,,,,,,,,,,0 diff --git a/GPU/GPUTracking/Definitions/Parameters/GPUParameters.json b/GPU/GPUTracking/Definitions/Parameters/GPUParameters.json.example similarity index 100% rename from GPU/GPUTracking/Definitions/Parameters/GPUParameters.json rename to GPU/GPUTracking/Definitions/Parameters/GPUParameters.json.example diff --git a/GPU/GPUTracking/Standalone/cmake/config.cmake b/GPU/GPUTracking/Standalone/cmake/config.cmake index ca723063b6d3b..9355311db617c 100644 --- a/GPU/GPUTracking/Standalone/cmake/config.cmake +++ b/GPU/GPUTracking/Standalone/cmake/config.cmake @@ -41,3 +41,4 @@ set(CUDA_COMPUTETARGET "default") # 86 89 #set(GPUCA_CONFIG_COMPILER gcc) # gcc / clang #set(GPUCA_CONFIG_WERROR 1) #add_definitions(-DGPUCA_GPU_DEBUG_PRINT) +#set(GPUCA_OVERRIDE_PARAMETER_FILE "foo.csv") diff --git a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake index 0c3e905a697c0..5bf1454cb31d8 100644 --- a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake +++ b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake @@ -73,7 +73,6 @@ function(generate_macros json_content output types arch_list arch_list_output) endfunction() function(generate_gpu_param_header GPU_ARCH OUT_HEADER) - set(GPU_PARAM_JSON ${CMAKE_CURRENT_SOURCE_DIR}/Definitions/Parameters/GPUParameters.json) set(TARGET_ARCH "UNKNOWN") if(GPU_ARCH STREQUAL "AUTO") detect_gpu_arch("ALL") From fe395fea62618db410e4703f00e9f233e5a6ac44 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 5 Feb 2026 22:54:07 +0100 Subject: [PATCH 159/234] GPU CMake: Use FILE GENERATE to generate Default Parameter Headers to track changes and rerun if necessary --- GPU/GPUTracking/CMakeLists.txt | 2 + .../cmake/gpu_param_header_generator.cmake | 40 ++++++++----------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index cd17d8f284b13..14118d9b71e9c 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -112,6 +112,8 @@ if(GPUCA_OVERRIDE_PARAMETER_FILE) else() set(GPU_PARAM_JSON ${CMAKE_CURRENT_SOURCE_DIR}/Definitions/Parameters/GPUParameters.csv) endif() +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${GPU_PARAM_JSON}") + get_filename_component(GPU_PARAM_JSON_EXT ${GPU_PARAM_JSON} EXT) string(TOLOWER "${GPU_PARAM_JSON_EXT}" GPU_PARAM_JSON_EXT) if(GPU_PARAM_JSON_EXT STREQUAL .csv) diff --git a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake index 5bf1454cb31d8..e79a96034103d 100644 --- a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake +++ b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake @@ -80,17 +80,15 @@ function(generate_gpu_param_header GPU_ARCH OUT_HEADER) set(TARGET_ARCH ${GPU_ARCH}) endif() file(READ "${GPU_PARAM_JSON}" JSON_CONTENT) - set(TMP_HEADER "${OUT_HEADER}.tmp") - file(WRITE "${TMP_HEADER}" "#ifndef GPUDEFPARAMETERSDEFAULTS_H\n#define GPUDEFPARAMETERSDEFAULTS_H\n\n") - file(APPEND "${TMP_HEADER}" "// This file is auto-generated from gpu_params.json. Do not edit directly.\n") + set(TMP_HEADER "#ifndef GPUDEFPARAMETERSDEFAULTS_H\n#define GPUDEFPARAMETERSDEFAULTS_H\n\n") + string(APPEND TMP_HEADER "// This file is auto-generated from gpu_params.json. Do not edit directly.\n") string(REPLACE "," ";" ARCH_LIST "${TARGET_ARCH}") - file(APPEND "${TMP_HEADER}" "// Architectures: ${TARGET_ARCH}\n\n") - file(APPEND "${TMP_HEADER}" "#if defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_NO_LAUNCH_BOUNDS) // Avoid including for RTC generation besides normal include protection.\n\n") + string(APPEND TMP_HEADER "// Architectures: ${TARGET_ARCH}\n\n") + string(APPEND TMP_HEADER "#if defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_NO_LAUNCH_BOUNDS) // Avoid including for RTC generation besides normal include protection.\n\n") # Types set(TYPES CORE LB PAR) # Per architecture definitions - set(_first TRUE) generate_macros("${JSON_CONTENT}" TMP_OUTPUT "${TYPES}" "${ARCH_LIST};default;default_cpu" "JSON_ARCHITECTURES") list(FIND ARCH_LIST "ALL" do_all_architectures) if(ARGC GREATER 2) @@ -99,31 +97,25 @@ function(generate_gpu_param_header GPU_ARCH OUT_HEADER) if(do_all_architectures GREATER -1) set(ARCH_LIST ${JSON_ARCHITECTURES}) endif() + string(APPEND TMP_HEADER "#if 0\n") foreach(ARCH IN LISTS ARCH_LIST) - if(_first) - file(APPEND "${TMP_HEADER}" "#if defined(GPUCA_GPUTYPE_${ARCH})\n\n") - set(_first FALSE) - else() - file(APPEND "${TMP_HEADER}" "#elif defined(GPUCA_GPUTYPE_${ARCH})\n\n") - endif() - file(APPEND "${TMP_HEADER}" ${TMP_OUTPUT_${ARCH}}) + string(APPEND TMP_HEADER "\n#elif defined(GPUCA_GPUTYPE_${ARCH})\n") + string(APPEND TMP_HEADER ${TMP_OUTPUT_${ARCH}}) endforeach() - if(NOT _first) - file(APPEND "${TMP_HEADER}" "#else\n#error GPU TYPE NOT SET\n#endif\n") - endif() + string(APPEND TMP_HEADER "#else\n#error GPU TYPE NOT SET\n#endif\n") # Default parameters - file(APPEND "${TMP_HEADER}" "\n// Default parameters if not defined for the target architecture\n\n") - file(APPEND "${TMP_HEADER}" ${TMP_OUTPUT_default}) - file(APPEND "${TMP_HEADER}" "#endif // defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_NO_LAUNCH_BOUNDS)\n\n") + string(APPEND TMP_HEADER "\n// Default parameters if not defined for the target architecture\n\n") + string(APPEND TMP_HEADER ${TMP_OUTPUT_default}) + string(APPEND TMP_HEADER "#endif // defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_NO_LAUNCH_BOUNDS)\n\n") # CPU fallback - file(APPEND "${TMP_HEADER}" "#ifndef GPUCA_GPUCODE_GENRTC // Defaults for non-LB parameters also for CPU fallback\n\n") - file(APPEND "${TMP_HEADER}" ${TMP_OUTPUT_default_cpu}) - file(APPEND "${TMP_HEADER}" "\n#endif // GPUCA_GPUCODE_GENRTC\n") + string(APPEND TMP_HEADER "#ifndef GPUCA_GPUCODE_GENRTC // Defaults for non-LB parameters also for CPU fallback\n\n") + string(APPEND TMP_HEADER ${TMP_OUTPUT_default_cpu}) + string(APPEND TMP_HEADER "\n#endif // GPUCA_GPUCODE_GENRTC\n") - file(APPEND "${TMP_HEADER}" "\n#endif // GPUDEFPARAMETERSDEFAULTS_H\n") - file(RENAME "${TMP_HEADER}" "${OUT_HEADER}") + string(APPEND TMP_HEADER "\n#endif // GPUDEFPARAMETERSDEFAULTS_H\n") + file(GENERATE OUTPUT "${OUT_HEADER}" CONTENT "${TMP_HEADER}") message(STATUS "Generated ${OUT_HEADER}") add_custom_target(GPU_PARAM_HEADER_${GPU_ARCH}_ALL ALL DEPENDS ${OUT_HEADER} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/gpu_param_header_generator.cmake ${GPU_PARAM_JSON}) endfunction() From 6c63d01ba5c76408a9000db3a5c45cab39ea4611 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 6 Feb 2026 09:46:34 +0100 Subject: [PATCH 160/234] GPU CSV to JSON converter: Workaround to be compatible to MacOS --- GPU/GPUTracking/Definitions/Parameters/csv_to_json.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/GPU/GPUTracking/Definitions/Parameters/csv_to_json.sh b/GPU/GPUTracking/Definitions/Parameters/csv_to_json.sh index ae9d3b7704284..373bd18ba7cd4 100755 --- a/GPU/GPUTracking/Definitions/Parameters/csv_to_json.sh +++ b/GPU/GPUTracking/Definitions/Parameters/csv_to_json.sh @@ -2,7 +2,13 @@ [[ -z $1 ]] && { echo "Usage: csv_to_json.sh CSV_FILE"; exit 1; } -awk -vFPAT='([^,]*)|(\"([^\"]|\"\")*\")' \ +DELIM=$'\xFF' +sed -E \ + ':loop + s/^(([^"]*"[^"]*")*[^"]*),/\1'$DELIM'/; + t loop' \ + $1 | \ +awk -F$DELIM \ 'BEGIN { print "{" } { @@ -42,5 +48,4 @@ awk -vFPAT='([^,]*)|(\"([^\"]|\"\")*\")' \ if (paramprinted) print "\n }" if (catprinted) print " }" print "}" - }' \ - $1 + }' From c2cae5e77332edc5f876e2ff8de9d78f494fd795 Mon Sep 17 00:00:00 2001 From: ddobrigk Date: Sat, 7 Feb 2026 13:01:30 +0100 Subject: [PATCH 161/234] Add ability to retain TrackQA for all global tracks (#15010) * Add ability to retain TrackQA for all global tracks * Do check in one go for writeQAData * Change default to false * Change actual defaults to false --- .../AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h | 1 + Detectors/AOD/src/AODProducerWorkflowSpec.cxx | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h b/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h index 615a7f96de13e..2d16f343dc1eb 100644 --- a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h +++ b/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h @@ -237,6 +237,7 @@ class AODProducerWorkflowDPL : public Task bool mThinTracks{false}; bool mPropTracks{false}; bool mPropMuons{false}; + float mTrackQCKeepGlobalTracks{false}; float mTrackQCFraction{0.00}; int64_t mTrackQCNTrCut{4}; float mTrackQCDCAxy{3.}; diff --git a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx index b18514949114d..6dcb702791b43 100644 --- a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx +++ b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx @@ -499,7 +499,7 @@ void AODProducerWorkflowDPL::fillTrackTablesPerCollision(int collisionID, float weight = 0; static std::uniform_real_distribution<> distr(0., 1.); - bool writeQAData = o2::math_utils::Tsallis::downsampleTsallisCharged(data.getTrackParam(trackIndex).getPt(), mTrackQCFraction, mSqrtS, weight, distr(mGenerator)); + bool writeQAData = o2::math_utils::Tsallis::downsampleTsallisCharged(data.getTrackParam(trackIndex).getPt(), mTrackQCFraction, mSqrtS, weight, distr(mGenerator)) || (src != GIndex::TPC && mTrackQCKeepGlobalTracks); auto extraInfoHolder = processBarrelTrack(collisionID, collisionBC, trackIndex, data, bcsMap); if (writeQAData) { @@ -1719,6 +1719,7 @@ void AODProducerWorkflowDPL::init(InitContext& ic) LOGP(warn, "Specified non-default empty streamer mask!"); } } + mTrackQCKeepGlobalTracks = ic.options().get("trackqc-keepglobaltracks"); mTrackQCFraction = ic.options().get("trackqc-fraction"); mTrackQCNTrCut = ic.options().get("trackqc-NTrCut"); mTrackQCDCAxy = ic.options().get("trackqc-tpc-dca"); @@ -3348,6 +3349,7 @@ DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, boo ConfigParamSpec{"hepmc-update", VariantType::String, "always", {"When to update HepMC Aux tables: always - force update, never - never update, all - if all keys are present, any - when any key is present (not valid yet)"}}, ConfigParamSpec{"propagate-muons", VariantType::Bool, false, {"Propagate muons to IP"}}, ConfigParamSpec{"thin-tracks", VariantType::Bool, false, {"Produce thinned track tables"}}, + ConfigParamSpec{"trackqc-keepglobaltracks", VariantType::Bool, false, {"Always keep TrackQA for global tracks"}}, ConfigParamSpec{"trackqc-fraction", VariantType::Float, float(0.1), {"Fraction of tracks to QC"}}, ConfigParamSpec{"trackqc-NTrCut", VariantType::Int64, 4L, {"Minimal length of the track - in amount of tracklets"}}, ConfigParamSpec{"trackqc-tpc-dca", VariantType::Float, 3.f, {"Keep TPC standalone track with this DCAxy to the PV"}}, From 1dedc84cef1cc35cc858e31d47da7da51d361ecd Mon Sep 17 00:00:00 2001 From: shahor02 Date: Sat, 7 Feb 2026 13:02:06 +0100 Subject: [PATCH 162/234] Store TPC track A/C side info in the AO2D TrackExtra.fFlags unused bits (#15014) * Store TPC track A/C side info in TrackExtra.fFlags unused bits * Add dynamic columns hasTPCSideA/C, hasTPCSideAOnly/COnly, hasTPCBothSides --- Detectors/AOD/src/AODProducerWorkflowSpec.cxx | 6 ++++++ Framework/Core/include/Framework/AnalysisDataModel.h | 10 ++++++++++ Framework/Core/include/Framework/DataTypes.h | 2 ++ 3 files changed, 18 insertions(+) diff --git a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx index 6dcb702791b43..be169ad4be19d 100644 --- a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx +++ b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx @@ -2646,6 +2646,12 @@ AODProducerWorkflowDPL::TrackExtraInfo AODProducerWorkflowDPL::processBarrelTrac if (tpcOrig.getdEdx().dEdxTotTPC == 0) { extraInfoHolder.flags |= o2::aod::track::TPCdEdxAlt; } + if (tpcOrig.hasASideClusters()) { + extraInfoHolder.flags |= o2::aod::track::TPCSideA; + } + if (tpcOrig.hasCSideClusters()) { + extraInfoHolder.flags |= o2::aod::track::TPCSideC; + } extraInfoHolder.tpcInnerParam = tpcOrig.getP() / tpcOrig.getAbsCharge(); extraInfoHolder.tpcChi2NCl = tpcOrig.getNClusters() ? tpcOrig.getChi2() / tpcOrig.getNClusters() : 0; extraInfoHolder.tpcSignal = dEdx.dEdxTotTPC; diff --git a/Framework/Core/include/Framework/AnalysisDataModel.h b/Framework/Core/include/Framework/AnalysisDataModel.h index b174f3858e165..e3032830beaac 100644 --- a/Framework/Core/include/Framework/AnalysisDataModel.h +++ b/Framework/Core/include/Framework/AnalysisDataModel.h @@ -404,6 +404,16 @@ DECLARE_SOA_DYNAMIC_COLUMN(HasTOF, hasTOF, //! Flag to check if track has a TOF [](uint8_t detectorMap) -> bool { return detectorMap & o2::aod::track::TOF; }); DECLARE_SOA_DYNAMIC_COLUMN(IsPVContributor, isPVContributor, //! Run 3: Has this track contributed to the collision vertex fit [](uint8_t flags) -> bool { return (flags & o2::aod::track::PVContributor) == o2::aod::track::PVContributor; }); +DECLARE_SOA_DYNAMIC_COLUMN(HasTPCSideA, hasTPCSideA, //! Run 3: Has this track TPC clusters from side A? + [](uint8_t flags) -> bool { return (flags & o2::aod::track::TPCSideA) == o2::aod::track::TPCSideA; }); +DECLARE_SOA_DYNAMIC_COLUMN(HasTPCSideAOnly, hasTPCSideAOnly, //! Run 3: Has this track TPC clusters from side A only? + [](uint8_t flags) -> bool { return (flags & (o2::aod::track::TPCSideA | o2::aod::track::TPCSideC)) == o2::aod::track::TPCSideA; }); +DECLARE_SOA_DYNAMIC_COLUMN(HasTPCSideC, hasTPCSideC, //! Run 3: Has this track TPC clusters from side C? + [](uint8_t flags) -> bool { return (flags & o2::aod::track::TPCSideC) == o2::aod::track::TPCSideC; }); +DECLARE_SOA_DYNAMIC_COLUMN(HasTPCSideCOnly, hasTPCSideCOnly, //! Run 3: Has this track TPC clusters from side C only? + [](uint8_t flags) -> bool { return (flags & (o2::aod::track::TPCSideA | o2::aod::track::TPCSideC)) == o2::aod::track::TPCSideC; }); +DECLARE_SOA_DYNAMIC_COLUMN(HasTPCBothSides, hasTPCBothSides, //! Run 3: Has this track TPC clusters from both side A and C? + [](uint8_t flags) -> bool { return (flags & (o2::aod::track::TPCSideA | o2::aod::track::TPCSideC)) == (o2::aod::track::TPCSideA || o2::aod::track::TPCSideC); }); DECLARE_SOA_DYNAMIC_COLUMN(PIDForTracking, pidForTracking, //! PID hypothesis used during tracking. See the constants in the class PID in PID.h [](uint32_t flags) -> uint32_t { return flags >> 28; }); DECLARE_SOA_DYNAMIC_COLUMN(TPCNClsFound, tpcNClsFound, //! Number of found TPC clusters diff --git a/Framework/Core/include/Framework/DataTypes.h b/Framework/Core/include/Framework/DataTypes.h index e273a78f8d0a2..3d49d6d3c03d0 100644 --- a/Framework/Core/include/Framework/DataTypes.h +++ b/Framework/Core/include/Framework/DataTypes.h @@ -51,6 +51,8 @@ enum TrackFlags : uint32_t { OrphanTrack = 0x4, // Track has no association with any collision vertex TrackTimeAsym = 0x8, // track with an asymmetric time range TPCdEdxAlt = 0x10, // TPCSignal and tpcNClsFindableMinusPID correspond for alternative dEdx since the nominal was 0 + TPCSideA = 0x20, // TPC track has A-side clusters (if any) + TPCSideC = 0x40, // TPC track has C-side clusters (if any) // NOTE Highest 4 (29..32) bits reserved for PID hypothesis }; enum TrackFlagsRun2Enum { From a9e312faaff4b436fdf839ea5bc45ed4c0049a4a Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 6 Feb 2026 10:37:15 +0100 Subject: [PATCH 163/234] GPU: Generate GPU parameter files only if GPU build is actually enabled --- GPU/GPUTracking/CMakeLists.txt | 48 +++++++++---------- .../Standalone/tools/dumpGPUDefParam.C | 2 +- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index 14118d9b71e9c..4ff1355672d7c 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -428,31 +428,6 @@ target_sources(${targetName} FILES ${GENERATED_HEADERS_LIST} BASE_DIRS ${CMAKE_CURRENT_BINARY_DIR}) -make_directory(${CMAKE_CURRENT_BINARY_DIR}/genGPUArch) -set(GPU_CONST_PARAM_FILES "") -set(GPU_ARCH_PARAMS_HEADER ${CMAKE_CURRENT_BINARY_DIR}/genGPUArch/GPUDefParametersDefaults_OnTheFly.h) -generate_gpu_param_header("ALL" ${GPU_ARCH_PARAMS_HEADER} "GPU_CONST_PARAM_ARCHITECTUES") -foreach(GPU_ARCH ${GPU_CONST_PARAM_ARCHITECTUES}) - set(PARAMFILE ${CMAKE_CURRENT_BINARY_DIR}/genGPUArch/gpu_const_param_${GPU_ARCH}.par) - add_custom_command( - OUTPUT ${PARAMFILE} - COMMAND bash -c - "echo -e '#define GPUCA_GPUTYPE_${GPU_ARCH}\\n#define PARAMETER_FILE \"${GPU_ARCH_PARAMS_HEADER}\"\\ngInterpreter->AddIncludePath(\"${CMAKE_CURRENT_SOURCE_DIR}/Definitions\");\\ngInterpreter->AddIncludePath(\"${ON_THE_FLY_DIR}\");\\n.x ${CMAKE_CURRENT_SOURCE_DIR}/Standalone/tools/dumpGPUDefParam.C(\"${PARAMFILE}\")\\n.q\\n'" - | root -l -b > /dev/null - VERBATIM - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/genGPUArch - MAIN_DEPENDENCY Standalone/tools/dumpGPUDefParam.C - DEPENDS ${GPU_ARCH_PARAMS_HEADER} - ${ON_THE_FLY_DIR}/GPUDefParametersLoadPrepare.h - ${ON_THE_FLY_DIR}/GPUDefParametersLoad.inc - COMMENT "Generating GPU parameter set for architecture ${GPU_ARCH}") - LIST(APPEND GPU_CONST_PARAM_FILES ${PARAMFILE}) -endforeach() - -add_custom_target(${MODULE}_GPU_CONST_PARAM_ARCHS ALL DEPENDS ${GPU_CONST_PARAM_FILES}) -install(FILES ${GPU_CONST_PARAM_FILES} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/GPU/arch_param) - - # Add compile definitions and libraries depending on available optional dependencies if(GPUCA_QA) message(STATUS "Building GPU QA") @@ -473,6 +448,29 @@ if(CUDA_ENABLED OR OPENCL_ENABLED OR HIP_ENABLED) if(CMAKE_SYSTEM_NAME MATCHES Darwin) message(WARNING "GPU Tracking disabled on MacOS") else() + make_directory(${CMAKE_CURRENT_BINARY_DIR}/genGPUArch) + set(GPU_CONST_PARAM_FILES "") + set(GPU_ARCH_PARAMS_HEADER ${CMAKE_CURRENT_BINARY_DIR}/genGPUArch/GPUDefParametersDefaults_OnTheFly.h) + generate_gpu_param_header("ALL" ${GPU_ARCH_PARAMS_HEADER} "GPU_CONST_PARAM_ARCHITECTUES") + foreach(GPU_ARCH ${GPU_CONST_PARAM_ARCHITECTUES}) + set(PARAMFILE ${CMAKE_CURRENT_BINARY_DIR}/genGPUArch/gpu_const_param_${GPU_ARCH}.par) + add_custom_command( + OUTPUT ${PARAMFILE} + COMMAND bash -c + "echo -e '#define GPUCA_GPUTYPE_${GPU_ARCH}\\n#define PARAMETER_FILE \"${GPU_ARCH_PARAMS_HEADER}\"\\ngInterpreter->AddIncludePath(\"${CMAKE_CURRENT_SOURCE_DIR}/Definitions\");\\ngInterpreter->AddIncludePath(\"${ON_THE_FLY_DIR}\");\\n.x ${CMAKE_CURRENT_SOURCE_DIR}/Standalone/tools/dumpGPUDefParam.C(\"${PARAMFILE}\")\\n.q\\n'" + | root -l -b > /dev/null + VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/genGPUArch + MAIN_DEPENDENCY Standalone/tools/dumpGPUDefParam.C + DEPENDS ${GPU_ARCH_PARAMS_HEADER} + ${ON_THE_FLY_DIR}/GPUDefParametersLoadPrepare.h + ${ON_THE_FLY_DIR}/GPUDefParametersLoad.inc + COMMENT "Generating GPU parameter set for architecture ${GPU_ARCH}") + LIST(APPEND GPU_CONST_PARAM_FILES ${PARAMFILE}) + endforeach() + add_custom_target(${MODULE}_GPU_CONST_PARAM_ARCHS ALL DEPENDS ${GPU_CONST_PARAM_FILES}) + install(FILES ${GPU_CONST_PARAM_FILES} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/GPU/arch_param) + if(CUDA_ENABLED) add_subdirectory(Base/cuda) endif() diff --git a/GPU/GPUTracking/Standalone/tools/dumpGPUDefParam.C b/GPU/GPUTracking/Standalone/tools/dumpGPUDefParam.C index f6866bb80da05..30d10bcdd2a8e 100644 --- a/GPU/GPUTracking/Standalone/tools/dumpGPUDefParam.C +++ b/GPU/GPUTracking/Standalone/tools/dumpGPUDefParam.C @@ -18,7 +18,7 @@ // echo -e '#define GPUCA_GPUTYPE_AMPERE\n#define PARAMETER_FILE "GPUDefParametersDefaults.h"\ngInterpreter->AddIncludePath("'`pwd`'/include/GPU");\n.x share/GPU/tools/dumpGPUDefParam.C("default_AMPERE.par")\n.q\n' | root -l -b #ifndef PARAMETER_FILE -#error Must provide the PARAMETER_FILE as preprocessor define, e.g. -DHEADER_TO_INCLUDE='"GPUDefParametersDefaults.h"' +#error Must provide the PARAMETER_FILE as preprocessor define, e.g. -DPARAMETER_FILE='"GPUDefParametersDefaults.h"' #endif #define GPUCA_GPUCODE From acd7f3bcd98bb944f2e0ff44b855c342161cfe2c Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 6 Feb 2026 12:24:28 +0100 Subject: [PATCH 164/234] GPU Parameter CSV: sort such that defaults are first --- .../Definitions/Parameters/GPUParameters.csv | 140 +++++++++--------- .../Definitions/Parameters/json_to_csv.python | 1 + 2 files changed, 71 insertions(+), 70 deletions(-) diff --git a/GPU/GPUTracking/Definitions/Parameters/GPUParameters.csv b/GPU/GPUTracking/Definitions/Parameters/GPUParameters.csv index 5afa99554f5d0..fc27de72ea2f1 100644 --- a/GPU/GPUTracking/Definitions/Parameters/GPUParameters.csv +++ b/GPU/GPUTracking/Definitions/Parameters/GPUParameters.csv @@ -1,72 +1,72 @@ -Architecture,default,MI100,VEGA,TAHITI,TESLA,FERMI,PASCAL,KEPLER,AMPERE,TURING,default_cpu +Architecture,default,default_cpu,MI100,VEGA,TAHITI,TESLA,FERMI,PASCAL,KEPLER,AMPERE,TURING ,,,,,,,,,,, CORE:,,,,,,,,,,, -WARP_SIZE,32,64,64,32,32,32,32,32,32,32, -THREAD_COUNT_DEFAULT,256,256,256,,,,,,512,512, +WARP_SIZE,32,,64,64,32,32,32,32,32,32,32 +THREAD_COUNT_DEFAULT,256,,256,256,,,,,,512,512 ,,,,,,,,,,, LB:,,,,,,,,,,, -GPUTPCCreateTrackingData,256,"[256, 7]","[192, 2]",,,,,,384,256, -GPUTPCTrackletConstructor,256,"[768, 8]","[512, 10]","[256, 2]","[256, 1]","[256, 2]","[1024, 2]","[512, 4]","[256, 2]","[256, 2]", -GPUTPCTrackletSelector,256,"[384, 5]","[192, 10]","[256, 3]","[256, 1]","[256, 3]","[512, 4]","[256, 3]","[192, 3]","[192, 3]", -GPUTPCNeighboursFinder,256,"[192, 8]","[960, 8]",256,256,256,512,256,"[640, 1]","[640, 1]", -GPUTPCNeighboursCleaner,256,"[128, 5]","[384, 9]",256,256,256,256,256,512,512, -GPUTPCExtrapolationTracking,256,"[256, 7]","[256, 2]",,,,,,"[128, 4]","[192, 2]", +GPUTPCCreateTrackingData,256,,"[256, 7]","[192, 2]",,,,,,384,256 +GPUTPCTrackletConstructor,256,,"[768, 8]","[512, 10]","[256, 2]","[256, 1]","[256, 2]","[1024, 2]","[512, 4]","[256, 2]","[256, 2]" +GPUTPCTrackletSelector,256,,"[384, 5]","[192, 10]","[256, 3]","[256, 1]","[256, 3]","[512, 4]","[256, 3]","[192, 3]","[192, 3]" +GPUTPCNeighboursFinder,256,,"[192, 8]","[960, 8]",256,256,256,512,256,"[640, 1]","[640, 1]" +GPUTPCNeighboursCleaner,256,,"[128, 5]","[384, 9]",256,256,256,256,256,512,512 +GPUTPCExtrapolationTracking,256,,"[256, 7]","[256, 2]",,,,,,"[128, 4]","[192, 2]" GPUTRDTrackerKernels_gpuVersion,512,,,,,,,,,, GPUTPCCreateOccupancyMap_fill,256,,,,,,,,,, GPUTPCCreateOccupancyMap_fold,256,,,,,,,,,, GPUTRDTrackerKernels_o2Version,512,,,,,,,,,, -GPUTPCCompressionKernels_step0attached,256,"[128, 1]","[64, 2]",,,,,,"[64, 2]",128, -GPUTPCCompressionKernels_step1unattached,256,"[512, 2]","[512, 2]",,,,,,"[512, 3]","[512, 2]", -GPUTPCDecompressionKernels_step0attached,256,"[128, 2]","[128, 2]",,,,,,"[32, 1]","[32, 1]", -GPUTPCDecompressionKernels_step1unattached,256,"[64, 2]","[64, 2]",,,,,,"[32, 1]","[32, 1]", +GPUTPCCompressionKernels_step0attached,256,,"[128, 1]","[64, 2]",,,,,,"[64, 2]",128 +GPUTPCCompressionKernels_step1unattached,256,,"[512, 2]","[512, 2]",,,,,,"[512, 3]","[512, 2]" +GPUTPCDecompressionKernels_step0attached,256,,"[128, 2]","[128, 2]",,,,,,"[32, 1]","[32, 1]" +GPUTPCDecompressionKernels_step1unattached,256,,"[64, 2]","[64, 2]",,,,,,"[32, 1]","[32, 1]" GPUTPCDecompressionUtilKernels_sortPerSectorRow,256,,,,,,,,,, GPUTPCDecompressionUtilKernels_countFilteredClusters,256,,,,,,,,,, GPUTPCDecompressionUtilKernels_storeFilteredClusters,256,,,,,,,,,, -GPUTPCCFDecodeZS,"[128, 4]","[64, 4]","[64, 1]",,,,,,"[64, 10]","[64, 8]", -GPUTPCCFDecodeZSLink,"""GPUCA_WARP_SIZE""","""GPUCA_WARP_SIZE""","""GPUCA_WARP_SIZE""",,,,,,"""GPUCA_WARP_SIZE""","""GPUCA_WARP_SIZE""", -GPUTPCCFDecodeZSDenseLink,"""GPUCA_WARP_SIZE""","[""GPUCA_WARP_SIZE"", 4]","[""GPUCA_WARP_SIZE"", 14]",,,,,,"""GPUCA_WARP_SIZE""","""GPUCA_WARP_SIZE""", -GPUTPCCFGather,"[1024, 1]","[1024, 5]","[1024, 1]",,,,,,"[1024, 1]","[1024, 1]", -COMPRESSION_GATHER,1024,1024,1024,,,,,,1024,1024, -GPUTPCGMMergerTrackFit,256,"[192, 2]","[64, 7]",,,,,,"[64, 4]","[32, 8]", -GPUTPCGMMergerFollowLoopers,256,"[256, 5]","[256, 4]",,,,,,"[64, 12]","[128, 4]", -GPUTPCGMMergerSectorRefit,256,"[64, 4]","[256, 2]",,,,,,"[32, 6]","[64, 5]", -GPUTPCGMMergerUnpackResetIds,256,256,256,,,,,,256,256, -GPUTPCGMMergerUnpackGlobal,256,256,256,,,,,,256,256, -GPUTPCGMMergerResolve_step0,256,512,256,,,,,,256,256, -GPUTPCGMMergerResolve_step1,256,512,256,,,,,,256,256, -GPUTPCGMMergerResolve_step2,256,512,256,,,,,,256,256, -GPUTPCGMMergerResolve_step3,256,512,256,,,,,,256,256, -GPUTPCGMMergerResolve_step4,256,512,256,,,,,,"[256, 4]","[256, 4]", -GPUTPCGMMergerClearLinks,256,256,256,,,,,,256,256, -GPUTPCGMMergerMergeWithinPrepare,256,256,256,,,,,,256,256, -GPUTPCGMMergerMergeSectorsPrepare,256,256,256,,,,,,"[256, 2]","[256, 2]", -GPUTPCGMMergerMergeBorders_step0,256,512,256,,,,,,192,192, -GPUTPCGMMergerMergeBorders_step2,256,512,256,,,,,,"[64, 2]",256, -GPUTPCGMMergerMergeCE,256,512,256,,,,,,256,256, -GPUTPCGMMergerLinkExtrapolatedTracks,256,256,256,,,,,,256,256, -GPUTPCGMMergerCollect,256,"[768, 1]","[1024, 1]",,,,,,"[256, 2]","[128, 2]", -GPUTPCGMMergerSortTracksPrepare,256,256,256,,,,,,256,256, -GPUTPCGMMergerPrepareForFit_step0,256,256,256,,,,,,256,256, -GPUTPCGMMergerPrepareForFit_step1,256,256,256,,,,,,256,256, -GPUTPCGMMergerPrepareForFit_step2,256,256,256,,,,,,256,256, -GPUTPCGMMergerFinalize_step0,256,,256,,,,,,,, -GPUTPCGMMergerFinalize_step1,256,,256,,,,,,,, -GPUTPCGMMergerFinalize_step2,256,,256,,,,,,,, +GPUTPCCFDecodeZS,"[128, 4]",,"[64, 4]","[64, 1]",,,,,,"[64, 10]","[64, 8]" +GPUTPCCFDecodeZSLink,"""GPUCA_WARP_SIZE""",,"""GPUCA_WARP_SIZE""","""GPUCA_WARP_SIZE""",,,,,,"""GPUCA_WARP_SIZE""","""GPUCA_WARP_SIZE""" +GPUTPCCFDecodeZSDenseLink,"""GPUCA_WARP_SIZE""",,"[""GPUCA_WARP_SIZE"", 4]","[""GPUCA_WARP_SIZE"", 14]",,,,,,"""GPUCA_WARP_SIZE""","""GPUCA_WARP_SIZE""" +GPUTPCCFGather,"[1024, 1]",,"[1024, 5]","[1024, 1]",,,,,,"[1024, 1]","[1024, 1]" +COMPRESSION_GATHER,1024,,1024,1024,,,,,,1024,1024 +GPUTPCGMMergerTrackFit,256,,"[192, 2]","[64, 7]",,,,,,"[64, 4]","[32, 8]" +GPUTPCGMMergerFollowLoopers,256,,"[256, 5]","[256, 4]",,,,,,"[64, 12]","[128, 4]" +GPUTPCGMMergerSectorRefit,256,,"[64, 4]","[256, 2]",,,,,,"[32, 6]","[64, 5]" +GPUTPCGMMergerUnpackResetIds,256,,256,256,,,,,,256,256 +GPUTPCGMMergerUnpackGlobal,256,,256,256,,,,,,256,256 +GPUTPCGMMergerResolve_step0,256,,512,256,,,,,,256,256 +GPUTPCGMMergerResolve_step1,256,,512,256,,,,,,256,256 +GPUTPCGMMergerResolve_step2,256,,512,256,,,,,,256,256 +GPUTPCGMMergerResolve_step3,256,,512,256,,,,,,256,256 +GPUTPCGMMergerResolve_step4,256,,512,256,,,,,,"[256, 4]","[256, 4]" +GPUTPCGMMergerClearLinks,256,,256,256,,,,,,256,256 +GPUTPCGMMergerMergeWithinPrepare,256,,256,256,,,,,,256,256 +GPUTPCGMMergerMergeSectorsPrepare,256,,256,256,,,,,,"[256, 2]","[256, 2]" +GPUTPCGMMergerMergeBorders_step0,256,,512,256,,,,,,192,192 +GPUTPCGMMergerMergeBorders_step2,256,,512,256,,,,,,"[64, 2]",256 +GPUTPCGMMergerMergeCE,256,,512,256,,,,,,256,256 +GPUTPCGMMergerLinkExtrapolatedTracks,256,,256,256,,,,,,256,256 +GPUTPCGMMergerCollect,256,,"[768, 1]","[1024, 1]",,,,,,"[256, 2]","[128, 2]" +GPUTPCGMMergerSortTracksPrepare,256,,256,256,,,,,,256,256 +GPUTPCGMMergerPrepareForFit_step0,256,,256,256,,,,,,256,256 +GPUTPCGMMergerPrepareForFit_step1,256,,256,256,,,,,,256,256 +GPUTPCGMMergerPrepareForFit_step2,256,,256,256,,,,,,256,256 +GPUTPCGMMergerFinalize_step0,256,,,256,,,,,,, +GPUTPCGMMergerFinalize_step1,256,,,256,,,,,,, +GPUTPCGMMergerFinalize_step2,256,,,256,,,,,,, GPUTPCGMMergerMergeLoopers_step0,256,,,,,,,,,, GPUTPCGMMergerMergeLoopers_step1,256,,,,,,,,,, GPUTPCGMMergerMergeLoopers_step2,256,,,,,,,,,, GPUTPCGMO2Output_prepare,256,,,,,,,,,, GPUTPCGMO2Output_output,256,,,,,,,,,, -GPUTPCStartHitsFinder,256,"[1024, 2]","[1024, 7]",256,256,256,256,256,512,512, -GPUTPCStartHitsSorter,256,"[1024, 5]","[512, 7]",256,256,256,256,256,"[512, 1]","[512, 1]", -GPUTPCCFCheckPadBaseline,576,"[576, 2]","[576, 2]",,,,,,"[576, 2]",, -GPUTPCCFChargeMapFiller_fillIndexMap,512,512,512,,,,,,448,, -GPUTPCCFChargeMapFiller_fillFromDigits,512,512,512,,,,,,448,, -GPUTPCCFChargeMapFiller_findFragmentStart,512,512,512,,,,,,448,, -GPUTPCCFPeakFinder,512,"[512, 9]","[512, 4]",,,,,,128,, -GPUTPCCFNoiseSuppression,512,512,512,,,,,,448,, -GPUTPCCFDeconvolution,512,"[512, 5]","[512, 5]",,,,,,384,, -GPUTPCCFClusterizer,512,"[448, 3]","[512, 2]",,,,,,448,, +GPUTPCStartHitsFinder,256,,"[1024, 2]","[1024, 7]",256,256,256,256,256,512,512 +GPUTPCStartHitsSorter,256,,"[1024, 5]","[512, 7]",256,256,256,256,256,"[512, 1]","[512, 1]" +GPUTPCCFCheckPadBaseline,576,,"[576, 2]","[576, 2]",,,,,,"[576, 2]", +GPUTPCCFChargeMapFiller_fillIndexMap,512,,512,512,,,,,,448, +GPUTPCCFChargeMapFiller_fillFromDigits,512,,512,512,,,,,,448, +GPUTPCCFChargeMapFiller_findFragmentStart,512,,512,512,,,,,,448, +GPUTPCCFPeakFinder,512,,"[512, 9]","[512, 4]",,,,,,128, +GPUTPCCFNoiseSuppression,512,,512,512,,,,,,448, +GPUTPCCFDeconvolution,512,,"[512, 5]","[512, 5]",,,,,,384, +GPUTPCCFClusterizer,512,,"[448, 3]","[512, 2]",,,,,,448, GPUTPCNNClusterizerKernels,512,,,,,,,,,, GPUTrackingRefitKernel_mode0asGPU,256,,,,,,,,,, GPUTrackingRefitKernel_mode1asTrackParCov,256,,,,,,,,,, @@ -92,22 +92,22 @@ GPUTPCCompressionGatherKernels_buffered32,"""GPUCA_LB_COMPRESSION_GATHER""",,,,, GPUTPCCompressionGatherKernels_buffered64,"""GPUCA_LB_COMPRESSION_GATHER""",,,,,,,,,, GPUTPCCompressionGatherKernels_buffered128,"""GPUCA_LB_COMPRESSION_GATHER""",,,,,,,,,, GPUTPCCompressionGatherKernels_multiBlock,"""GPUCA_LB_COMPRESSION_GATHER""",,,,,,,,,, -GPUTPCGMMergerFinalize_0,256,256,,,,,,,256,256, -GPUTPCGMMergerFinalize_1,256,256,,,,,,,256,256, -GPUTPCGMMergerFinalize_2,256,256,,,,,,,256,256, +GPUTPCGMMergerFinalize_0,256,,256,,,,,,,256,256 +GPUTPCGMMergerFinalize_1,256,,256,,,,,,,256,256 +GPUTPCGMMergerFinalize_2,256,,256,,,,,,,256,256 ,,,,,,,,,,, PAR:,,,,,,,,,,, -AMD_EUS_PER_CU,0,4,4,,,,,,,,0 -SORT_STARTHITS,1,,,,,,,,,,0 -NEIGHBOURS_FINDER_MAX_NNEIGHUP,6,10,4,,,,,,4,4,0 -NEIGHBOURS_FINDER_UNROLL_GLOBAL,4,4,2,,,,,,,,0 -NEIGHBOURS_FINDER_UNROLL_SHARED,1,0,0,,,,,,,,0 -TRACKLET_SELECTOR_HITS_REG_SIZE,12,9,27,,,,,,20,20,0 -ALTERNATE_BORDER_SORT,0,1,1,,,,,,1,1,0 -SORT_BEFORE_FIT,0,1,1,,,,,,1,1,0 -NO_ATOMIC_PRECHECK,0,1,1,,,,,,1,1,0 -DEDX_STORAGE_TYPE,"""float""","""uint16_t""","""uint16_t""",,,,,,"""uint16_t""","""uint16_t""","""float""" -MERGER_INTERPOLATION_ERROR_TYPE,"""float""","""half""","""half""",,,,,,"""half""","""half""","""float""" -COMP_GATHER_KERNEL,0,4,4,,,,,,4,4,0 -COMP_GATHER_MODE,2,3,3,,,,,,3,3,0 -CF_SCAN_WORKGROUP_SIZE,512,,,,,,,,,,0 +AMD_EUS_PER_CU,0,0,4,4,,,,,,, +SORT_STARTHITS,1,0,,,,,,,,, +NEIGHBOURS_FINDER_MAX_NNEIGHUP,6,0,10,4,,,,,,4,4 +NEIGHBOURS_FINDER_UNROLL_GLOBAL,4,0,4,2,,,,,,, +NEIGHBOURS_FINDER_UNROLL_SHARED,1,0,0,0,,,,,,, +TRACKLET_SELECTOR_HITS_REG_SIZE,12,0,9,27,,,,,,20,20 +ALTERNATE_BORDER_SORT,0,0,1,1,,,,,,1,1 +SORT_BEFORE_FIT,0,0,1,1,,,,,,1,1 +NO_ATOMIC_PRECHECK,0,0,1,1,,,,,,1,1 +DEDX_STORAGE_TYPE,"""float""","""float""","""uint16_t""","""uint16_t""",,,,,,"""uint16_t""","""uint16_t""" +MERGER_INTERPOLATION_ERROR_TYPE,"""float""","""float""","""half""","""half""",,,,,,"""half""","""half""" +COMP_GATHER_KERNEL,0,0,4,4,,,,,,4,4 +COMP_GATHER_MODE,2,0,3,3,,,,,,3,3 +CF_SCAN_WORKGROUP_SIZE,512,0,,,,,,,,, diff --git a/GPU/GPUTracking/Definitions/Parameters/json_to_csv.python b/GPU/GPUTracking/Definitions/Parameters/json_to_csv.python index a6640239604e0..1ae15662021a3 100755 --- a/GPU/GPUTracking/Definitions/Parameters/json_to_csv.python +++ b/GPU/GPUTracking/Definitions/Parameters/json_to_csv.python @@ -27,6 +27,7 @@ for cat in data.values(): cols = 1 + len(arches) empty = [""] * cols +arches = sorted(arches, key=lambda x: 0 if x.startswith("default") else 1) with open(sys.argv[2], "w", newline="") as f: w = csv.writer(f, lineterminator="\n") From f182c291126a2875decfa42eb1bcad743c18f618 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sat, 7 Feb 2026 14:03:20 +0100 Subject: [PATCH 165/234] GPU CMake: Better detection of GPU optimization setting from architecture string --- dependencies/FindO2GPU.cmake | 48 +++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/dependencies/FindO2GPU.cmake b/dependencies/FindO2GPU.cmake index ec6b7323ad5d1..928454f93b4f8 100644 --- a/dependencies/FindO2GPU.cmake +++ b/dependencies/FindO2GPU.cmake @@ -46,30 +46,48 @@ endif() function(detect_gpu_arch backend) # Detect GPU architecture, optionally filterring by backend - if(CUDA_COMPUTETARGET AND CUDA_COMPUTETARGET MATCHES "86|89") + string(REGEX MATCH "^[ \t\r\n]*[0-9]+" CUDA_FIRST_TARGET "${CUDA_COMPUTETARGET}") + string(STRIP "${CUDA_FIRST_TARGET}" CUDA_FIRST_TARGET) + if(NOT CUDA_FIRST_TARGET) + set(CUDA_FIRST_TARGET 86) + message(STATUS "CUDA_COMPUTETARGET not set, defaulting CUDA optimization for architecture ${CUDA_FIRST_TARGET}") + endif() + if(CUDA_FIRST_TARGET GREATER_EQUAL 86) set(CUDA_TARGET AMPERE) - message(STATUS "Using optimized CUDA settings for Ampere GPU") - elseif(CUDA_COMPUTETARGET AND CUDA_COMPUTETARGET MATCHES "75") + elseif(CUDA_FIRST_TARGET GREATER_EQUAL 75) set(CUDA_TARGET TURING) - message(STATUS "Using optimized CUDA settings for Turing GPU") + elseif(CUDA_FIRST_TARGET GREATER_EQUAL 60) + set(CUDA_TARGET PASCAL) + elseif(CUDA_FIRST_TARGET GREATER_EQUAL 30) + set(CUDA_TARGET KEPLER) + elseif(CUDA_FIRST_TARGET GREATER_EQUAL 20) + set(CUDA_TARGET FERMI) else() - set(CUDA_TARGET AMPERE) - message(STATUS "Defaulting optimized CUDA settings for Ampere GPU") + set(CUDA_TARGET TESLA) endif() + message(STATUS "Using optimized CUDA settings for ${CUDA_TARGET} GPU (sm_${CUDA_FIRST_TARGET})") - if(HIP_AMDGPUTARGET AND HIP_AMDGPUTARGET MATCHES "gfx906") - set(HIP_TARGET VEGA) - message(STATUS "Using optimized HIP settings for MI50 GPU") - elseif(HIP_AMDGPUTARGET AND HIP_AMDGPUTARGET MATCHES "gfx908") - set(HIP_TARGET MI100) - message(STATUS "Using optimized HIP settings for MI100 GPU") - elseif(HIP_AMDGPUTARGET AND HIP_AMDGPUTARGET MATCHES "gfx90a") + string(REGEX MATCH "^[ \t\r\n]*gfx[0-9]+" HIP_FIRST_TARGET "${HIP_AMDGPUTARGET}") + string(STRIP "${HIP_FIRST_TARGET}" HIP_FIRST_TARGET) + string(REGEX REPLACE "^gfx" "" HIP_FIRST_TARGET "${HIP_FIRST_TARGET}") + if(NOT HIP_FIRST_TARGET) + set(HIP_FIRST_TARGET 906) + message(STATUS "HIP_AMDGPUTARGET not set, defaulting HIP optimization for architecture ${HIP_FIRST_TARGET}") + endif() + string(TOLOWER "${HIP_FIRST_TARGET}" HIP_FIRST_TARGET) + string(REGEX MATCH "....$" HIP_FIRST_TARGET_PADDED "0000${HIP_FIRST_TARGET}") + if(HIP_FIRST_TARGET_PADDED STRGREATER_EQUAL "1000") + set(HIP_TARGET RDNA) + elseif(HIP_FIRST_TARGET_PADDED STRGREATER_EQUAL "090a") + set(HIP_TARGET MI210) + elseif(HIP_FIRST_TARGET_PADDED STRGREATER_EQUAL "0908") set(HIP_TARGET MI100) - message(STATUS "Using optimized HIP settings for MI210 GPU") + elseif(HIP_FIRST_TARGET_PADDED STRGREATER_EQUAL "0906") + set(HIP_TARGET VEGA) else() set(HIP_TARGET VEGA) - message(STATUS "Defaulting optimized HIP settings for VEGA GPU") endif() + message(STATUS "Using optimized HIP settings for ${HIP_TARGET} GPU (gfx${HIP_FIRST_TARGET})") if(backend STREQUAL "CUDA") # CUDA filter set(TARGET_ARCH "${CUDA_TARGET}" PARENT_SCOPE) From 6a9fd1e145c46fbe21c5a62999e59c8bc288a4b1 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 8 Feb 2026 00:05:43 +0100 Subject: [PATCH 166/234] GPU CMake: Write separate headers for GPU device and non-device parameters, use same headers for compilation and for parameter file generation --- GPU/GPUTracking/Base/cuda/CMakeLists.txt | 2 +- GPU/GPUTracking/Base/hip/CMakeLists.txt | 2 +- GPU/GPUTracking/CMakeLists.txt | 13 ++- .../cmake/gpu_param_header_generator.cmake | 106 +++++++++--------- dependencies/FindO2GPU.cmake | 17 ++- 5 files changed, 72 insertions(+), 68 deletions(-) diff --git a/GPU/GPUTracking/Base/cuda/CMakeLists.txt b/GPU/GPUTracking/Base/cuda/CMakeLists.txt index 226bacbf88157..27c3d24cd079f 100644 --- a/GPU/GPUTracking/Base/cuda/CMakeLists.txt +++ b/GPU/GPUTracking/Base/cuda/CMakeLists.txt @@ -74,7 +74,7 @@ add_custom_command( COMMAND cat ${GPUDIR}/Base/GPUStdSystemHeaders.h >> ${GPU_RTC_BIN}.src COMMAND ${CMAKE_CUDA_COMPILER} ${GPU_RTC_DEFINES} ${GPU_RTC_INCLUDES} -std=c++${CMAKE_CUDA_STANDARD} -D__CUDA_ARCH__=${RTC_CUDA_ARCH} -Wno-deprecated-gpu-targets -D__CUDACC__ -x c++ -M -MD -MT ${GPU_RTC_BIN}.src -MF ${GPU_RTC_BIN}.src.d ${GPU_RTC_SRC} COMMAND ${CMAKE_CUDA_COMPILER} ${GPU_RTC_DEFINES} ${GPU_RTC_INCLUDES} -std=c++${CMAKE_CUDA_STANDARD} -D__CUDA_ARCH__=${RTC_CUDA_ARCH} -Wno-deprecated-gpu-targets -D__CUDACC__ -x c++ -E -Xcompiler "-nostdinc -P" ${GPU_RTC_SRC} >> ${GPU_RTC_BIN}.src - DEPENDS ${GPU_RTC_SRC} ${GPUDIR}/Base/GPUStdSystemHeaders.h ${GPUDIR}/Base/cuda/GPUReconstructionCUDAIncludesSystem.h ${GPUDIR}/Base/GPUStdSystemHeaders.h GPU_PARAM_HEADER_AUTO_ALL + DEPENDS ${GPU_RTC_SRC} ${GPUDIR}/Base/GPUStdSystemHeaders.h ${GPUDIR}/Base/cuda/GPUReconstructionCUDAIncludesSystem.h ${GPUDIR}/Base/GPUStdSystemHeaders.h GPU_PARAM_HEADER_TARGET DEPFILE ${GPU_RTC_BIN}.src.d COMMAND_EXPAND_LISTS COMMENT "Preparing CUDA RTC source file ${GPU_RTC_BIN}.src" diff --git a/GPU/GPUTracking/Base/hip/CMakeLists.txt b/GPU/GPUTracking/Base/hip/CMakeLists.txt index d148e376abca9..b459a78b5789e 100644 --- a/GPU/GPUTracking/Base/hip/CMakeLists.txt +++ b/GPU/GPUTracking/Base/hip/CMakeLists.txt @@ -125,7 +125,7 @@ add_custom_command( COMMAND cat ${GPUDIR}/Base/hip/GPUReconstructionHIPIncludesSystem.h | grep -v GPUStdSystemHeaders.h >> ${GPU_RTC_BIN}.src COMMAND cat ${GPUDIR}/Base/GPUStdSystemHeaders.h >> ${GPU_RTC_BIN}.src COMMAND ${CMAKE_HIP_COMPILER} ${GPU_RTC_DEFINES} ${GPU_RTC_INCLUDES} -std=c++${CMAKE_HIP_STANDARD} -D__HIPCC__ -D__HIP_DEVICE_COMPILE__ -x c++ -nostdinc -E -P ${GPU_RTC_SRC} -MD -MT ${GPU_RTC_BIN}.src -MF ${GPU_RTC_BIN}.src.d >> ${GPU_RTC_BIN}.src - DEPENDS ${GPU_RTC_SRC} ${GPUDIR}/Base/GPUStdSystemHeaders.h ${GPUDIR}/Base/hip/GPUReconstructionHIPIncludesSystem.h ${GPUDIR}/Base/GPUStdSystemHeaders.h ${MODULE}_HIPIFIED GPU_PARAM_HEADER_AUTO_ALL + DEPENDS ${GPU_RTC_SRC} ${GPUDIR}/Base/GPUStdSystemHeaders.h ${GPUDIR}/Base/hip/GPUReconstructionHIPIncludesSystem.h ${GPUDIR}/Base/GPUStdSystemHeaders.h ${MODULE}_HIPIFIED GPU_PARAM_HEADER_TARGET DEPFILE ${GPU_RTC_BIN}.src.d COMMAND_EXPAND_LISTS COMMENT "Preparing HIP RTC source file ${GPU_RTC_BIN}.src" diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index 4ff1355672d7c..786774c16971b 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -130,7 +130,8 @@ set(ON_THE_FLY_DIR ${CMAKE_CURRENT_BINARY_DIR}/include_gpu_onthefly) file(MAKE_DIRECTORY ${ON_THE_FLY_DIR}) include(cmake/gpu_param_header_generator.cmake) set(GPU_DEFAULT_PARAMS_HEADER ${ON_THE_FLY_DIR}/GPUDefParametersDefaults.h) -generate_gpu_param_header("AUTO" ${GPU_DEFAULT_PARAMS_HEADER}) # generate header with default GPU parameters, arch selected by CMake variables +set(GPU_DEFAULT_PARAMS_HEADER_DEVICE ${ON_THE_FLY_DIR}/GPUDefParametersDefaultsDevice.h) +generate_gpu_param_header("ALL" ${GPU_DEFAULT_PARAMS_HEADER} ${GPU_DEFAULT_PARAMS_HEADER_DEVICE} GPU_CONST_PARAM_ARCHITECTUES) # generate header with default GPU parameters, arch selected by CMake variables set(HDRS_INSTALL ${HDRS_CINT_O2} @@ -161,6 +162,7 @@ set(HDRS_INSTALL Debug/GPUROOTDump.h Definitions/GPUDefConstantsAndSettings.h ${GPU_DEFAULT_PARAMS_HEADER} + ${GPU_DEFAULT_PARAMS_HEADER_DEVICE} Definitions/GPUDefParametersWrapper.h Definitions/GPUDefParametersConstants.h Definitions/GPUDef.h @@ -449,20 +451,19 @@ if(CUDA_ENABLED OR OPENCL_ENABLED OR HIP_ENABLED) message(WARNING "GPU Tracking disabled on MacOS") else() make_directory(${CMAKE_CURRENT_BINARY_DIR}/genGPUArch) - set(GPU_CONST_PARAM_FILES "") - set(GPU_ARCH_PARAMS_HEADER ${CMAKE_CURRENT_BINARY_DIR}/genGPUArch/GPUDefParametersDefaults_OnTheFly.h) - generate_gpu_param_header("ALL" ${GPU_ARCH_PARAMS_HEADER} "GPU_CONST_PARAM_ARCHITECTUES") + set(GPU_CONST_PARAM_FILES) foreach(GPU_ARCH ${GPU_CONST_PARAM_ARCHITECTUES}) set(PARAMFILE ${CMAKE_CURRENT_BINARY_DIR}/genGPUArch/gpu_const_param_${GPU_ARCH}.par) add_custom_command( OUTPUT ${PARAMFILE} COMMAND bash -c - "echo -e '#define GPUCA_GPUTYPE_${GPU_ARCH}\\n#define PARAMETER_FILE \"${GPU_ARCH_PARAMS_HEADER}\"\\ngInterpreter->AddIncludePath(\"${CMAKE_CURRENT_SOURCE_DIR}/Definitions\");\\ngInterpreter->AddIncludePath(\"${ON_THE_FLY_DIR}\");\\n.x ${CMAKE_CURRENT_SOURCE_DIR}/Standalone/tools/dumpGPUDefParam.C(\"${PARAMFILE}\")\\n.q\\n'" + "echo -e '#define GPUCA_GPUTYPE_${GPU_ARCH}\\n#define PARAMETER_FILE \"GPUDefParametersDefaults.h\"\\ngInterpreter->AddIncludePath(\"${CMAKE_CURRENT_SOURCE_DIR}/Definitions\");\\ngInterpreter->AddIncludePath(\"${ON_THE_FLY_DIR}\");\\n.x ${CMAKE_CURRENT_SOURCE_DIR}/Standalone/tools/dumpGPUDefParam.C(\"${PARAMFILE}\")\\n.q\\n'" | root -l -b > /dev/null VERBATIM WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/genGPUArch MAIN_DEPENDENCY Standalone/tools/dumpGPUDefParam.C - DEPENDS ${GPU_ARCH_PARAMS_HEADER} + DEPENDS ${GPU_DEFAULT_PARAMS_HEADER} + ${GPU_DEFAULT_PARAMS_HEADER_DEVICE} ${ON_THE_FLY_DIR}/GPUDefParametersLoadPrepare.h ${ON_THE_FLY_DIR}/GPUDefParametersLoad.inc COMMENT "Generating GPU parameter set for architecture ${GPU_ARCH}") diff --git a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake index e79a96034103d..31d395615a5ed 100644 --- a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake +++ b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake @@ -12,17 +12,31 @@ # file gpu_param_header_generator.cmake # author Gabriele Cimador -function(generate_macros json_content output types arch_list arch_list_output) - foreach(arch IN LISTS arch_list) - set(OUTPUT_TMP_${arch} "") - endforeach() - set(arch_list_output_tmp) - list(FIND arch_list "ALL" do_all_architectures) - foreach(TYPE IN LISTS types) - string(JSON n_params LENGTH "${json_content}" "${TYPE}") +function(generate_gpu_param_header ARCH_LIST OUT_HEADER OUT_HEADER_DEVICE) + list(FIND ARCH_LIST "ALL" do_all_architectures) + list(FIND ARCH_LIST "AUTO" do_auto_architectures) + if(do_all_architectures GREATER -1 OR do_auto_architectures GREATER -1) + if(do_auto_architectures GREATER -1) + detect_gpu_arch("AUTO") + list(REMOVE_ITEM ARCH_LIST "AUTO") + else() + detect_gpu_arch("ALL") + endif() + list(APPEND ARCH_LIST ${TARGET_ARCH}) + endif() + file(READ "${GPU_PARAM_JSON}" JSON_CONTENT) + + # Types + set(TYPES CORE LB PAR) + set(ARCH_LIST_EXT "${ARCH_LIST};default;default_cpu") + # Per architecture definitions + set(JSON_ARCHITECTURES) + + foreach(TYPE IN LISTS TYPES) + string(JSON n_params LENGTH "${JSON_CONTENT}" "${TYPE}") math(EXPR last "${n_params} - 1") foreach(i RANGE 0 ${last}) - string(JSON param_name MEMBER "${json_content}" "${TYPE}" "${i}") + string(JSON param_name MEMBER "${JSON_CONTENT}" "${TYPE}" "${i}") string(JSON n_archs LENGTH "${JSON_CONTENT}" "${TYPE}" "${param_name}") math(EXPR last_arch "${n_archs} - 1") foreach(iArch RANGE 0 ${last_arch}) @@ -31,12 +45,12 @@ function(generate_macros json_content output types arch_list arch_list_output) message(FATAL_ERROR "Bogus entry ${param_name} for ${arch}") endif() if(do_all_architectures GREATER -1) - if(arch_list_output AND NOT arch MATCHES ^default) - list(APPEND arch_list_output_tmp "${arch}") + if(NOT arch MATCHES ^default) + list(APPEND JSON_ARCHITECTURES "${arch}") endif() set(list_idx 0) else() - list(FIND arch_list "${arch}" list_idx) + list(FIND ARCH_LIST_EXT "${arch}" list_idx) endif() if(list_idx GREATER -1) string(JSON param_values GET "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${arch}") @@ -54,68 +68,58 @@ function(generate_macros json_content output types arch_list arch_list_output) set(MACRO_DEFINITION "#define ${MACRO_NAME} ${vals}") if(arch MATCHES ^default) # fallback defaults are wrapped in #ifndef - string(APPEND OUTPUT_TMP_${arch} "#ifndef ${MACRO_NAME}\n ${MACRO_DEFINITION}\n#endif\n\n") + string(APPEND generate_gpu_param_header_OUTPUT_TMP_${arch} "#ifndef ${MACRO_NAME}\n ${MACRO_DEFINITION}\n#endif\n\n") else() - string(APPEND OUTPUT_TMP_${arch} "${MACRO_DEFINITION}\n") + string(APPEND generate_gpu_param_header_OUTPUT_TMP_${arch} "${MACRO_DEFINITION}\n") endif() endif() endforeach() endforeach() endforeach() - foreach(arch IN LISTS arch_list) - set(${output}_${arch} "${OUTPUT_TMP_${arch}}" PARENT_SCOPE) - endforeach() - if(arch_list_output) - list(REMOVE_DUPLICATES arch_list_output_tmp) - list(SORT arch_list_output_tmp) - set(${arch_list_output} "${arch_list_output_tmp}" PARENT_SCOPE) - endif() -endfunction() -function(generate_gpu_param_header GPU_ARCH OUT_HEADER) - set(TARGET_ARCH "UNKNOWN") - if(GPU_ARCH STREQUAL "AUTO") - detect_gpu_arch("ALL") - else() - set(TARGET_ARCH ${GPU_ARCH}) + list(REMOVE_DUPLICATES JSON_ARCHITECTURES) + list(SORT JSON_ARCHITECTURES) + if(ARGC GREATER 3) + set(${ARGV3} "${JSON_ARCHITECTURES}" PARENT_SCOPE) endif() - file(READ "${GPU_PARAM_JSON}" JSON_CONTENT) + if(do_all_architectures GREATER -1) + list(REMOVE_ITEM ARCH_LIST "ALL") + list(APPEND ARCH_LIST ${JSON_ARCHITECTURES}) + endif() + list(REMOVE_DUPLICATES ARCH_LIST) + list(SORT ARCH_LIST) + + get_filename_component(DEVICE_HEADER_FILE "${OUT_HEADER_DEVICE}" NAME) + set(TMP_HEADER "#ifndef GPUDEFPARAMETERSDEFAULTS_H\n#define GPUDEFPARAMETERSDEFAULTS_H\n\n") + set(TMP_HEADER_DEVICE "#ifndef GPUDEFPARAMETERSDEFAULTSDEVICE_H\n#define GPUDEFPARAMETERSDEFAULTSDEVICE_H\n\n") string(APPEND TMP_HEADER "// This file is auto-generated from gpu_params.json. Do not edit directly.\n") - string(REPLACE "," ";" ARCH_LIST "${TARGET_ARCH}") - string(APPEND TMP_HEADER "// Architectures: ${TARGET_ARCH}\n\n") + string(APPEND TMP_HEADER_DEVICE "// This file is auto-generated from gpu_params.json. Do not edit directly.\n") + string(APPEND TMP_HEADER_DEVICE "// Architectures: ${TARGET_ARCH}\n\n") string(APPEND TMP_HEADER "#if defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_NO_LAUNCH_BOUNDS) // Avoid including for RTC generation besides normal include protection.\n\n") + string(APPEND TMP_HEADER "#include \"${DEVICE_HEADER_FILE}\"\n") - # Types - set(TYPES CORE LB PAR) - # Per architecture definitions - generate_macros("${JSON_CONTENT}" TMP_OUTPUT "${TYPES}" "${ARCH_LIST};default;default_cpu" "JSON_ARCHITECTURES") - list(FIND ARCH_LIST "ALL" do_all_architectures) - if(ARGC GREATER 2) - set(${ARGV2} "${JSON_ARCHITECTURES}" PARENT_SCOPE) - endif() - if(do_all_architectures GREATER -1) - set(ARCH_LIST ${JSON_ARCHITECTURES}) - endif() - string(APPEND TMP_HEADER "#if 0\n") + string(APPEND TMP_HEADER_DEVICE "#if 0\n") foreach(ARCH IN LISTS ARCH_LIST) - string(APPEND TMP_HEADER "\n#elif defined(GPUCA_GPUTYPE_${ARCH})\n") - string(APPEND TMP_HEADER ${TMP_OUTPUT_${ARCH}}) + string(APPEND TMP_HEADER_DEVICE "\n#elif defined(GPUCA_GPUTYPE_${ARCH})\n") + string(APPEND TMP_HEADER_DEVICE ${generate_gpu_param_header_OUTPUT_TMP_${ARCH}}) endforeach() - string(APPEND TMP_HEADER "#else\n#error GPU TYPE NOT SET\n#endif\n") + string(APPEND TMP_HEADER_DEVICE "#else\n#error GPU TYPE NOT SET\n#endif\n") # Default parameters string(APPEND TMP_HEADER "\n// Default parameters if not defined for the target architecture\n\n") - string(APPEND TMP_HEADER ${TMP_OUTPUT_default}) + string(APPEND TMP_HEADER ${generate_gpu_param_header_OUTPUT_TMP_default}) string(APPEND TMP_HEADER "#endif // defined(GPUCA_GPUCODE) && !defined(GPUCA_GPUCODE_GENRTC) && !defined(GPUCA_GPUCODE_NO_LAUNCH_BOUNDS)\n\n") # CPU fallback string(APPEND TMP_HEADER "#ifndef GPUCA_GPUCODE_GENRTC // Defaults for non-LB parameters also for CPU fallback\n\n") - string(APPEND TMP_HEADER ${TMP_OUTPUT_default_cpu}) + string(APPEND TMP_HEADER ${generate_gpu_param_header_OUTPUT_TMP_default_cpu}) string(APPEND TMP_HEADER "\n#endif // GPUCA_GPUCODE_GENRTC\n") string(APPEND TMP_HEADER "\n#endif // GPUDEFPARAMETERSDEFAULTS_H\n") + string(APPEND TMP_HEADER_DEVICE "\n#endif // GPUDEFPARAMETERSDEFAULTSDEVICE_H\n") file(GENERATE OUTPUT "${OUT_HEADER}" CONTENT "${TMP_HEADER}") - message(STATUS "Generated ${OUT_HEADER}") - add_custom_target(GPU_PARAM_HEADER_${GPU_ARCH}_ALL ALL DEPENDS ${OUT_HEADER} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/gpu_param_header_generator.cmake ${GPU_PARAM_JSON}) + file(GENERATE OUTPUT "${OUT_HEADER_DEVICE}" CONTENT "${TMP_HEADER_DEVICE}") + message(STATUS "Generated ${OUT_HEADER} and ${OUT_HEADER_DEVICE}") + add_custom_target(GPU_PARAM_HEADER_TARGET ALL DEPENDS ${OUT_HEADER} ${OUT_HEADER_DEVICE} ${GPU_PARAM_JSON}) endfunction() diff --git a/dependencies/FindO2GPU.cmake b/dependencies/FindO2GPU.cmake index 928454f93b4f8..42d0162691c37 100644 --- a/dependencies/FindO2GPU.cmake +++ b/dependencies/FindO2GPU.cmake @@ -93,18 +93,17 @@ function(detect_gpu_arch backend) # Detect GPU architecture, optionally filterri set(TARGET_ARCH "${CUDA_TARGET}" PARENT_SCOPE) elseif(backend STREQUAL "HIP") # HIP filter set(TARGET_ARCH "${HIP_TARGET}" PARENT_SCOPE) - elseif(backend STREQUAL "ALL") # Return enabled backends - set(_archs "") - if(CUDA_ENABLED) - list(APPEND _archs "${CUDA_TARGET}") + elseif(backend STREQUAL "ALL" OR backend STREQUAL "AUTO") # Return all / enabled backends + set(TARGET_ARCH) + if(CUDA_ENABLED OR backend STREQUAL "ALL") + list(APPEND TARGET_ARCH "${CUDA_TARGET}") endif() - if(HIP_ENABLED) - list(APPEND _archs "${HIP_TARGET}") + if(HIP_ENABLED OR backend STREQUAL "ALL") + list(APPEND TARGET_ARCH "${HIP_TARGET}") endif() - if(OPENCL_ENABLED) - list(APPEND _archs "OPENCL") + if(OPENCL_ENABLED OR backend STREQUAL "ALL") + list(APPEND TARGET_ARCH "OPENCL") endif() - list(JOIN _archs "," TARGET_ARCH) set(TARGET_ARCH "${TARGET_ARCH}" PARENT_SCOPE) else() message(FATAL_ERROR "Unknown backend provided: ${backend}") From f4becde9083aa6bb2dda8837a2a254eec4c55bb9 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 8 Feb 2026 23:25:16 +0100 Subject: [PATCH 167/234] GPU CMake: Clean up some targets, fix if JSON contains 0 architectures --- GPU/GPUTracking/Base/cuda/CMakeLists.txt | 2 +- GPU/GPUTracking/Base/hip/CMakeLists.txt | 2 +- GPU/GPUTracking/CMakeLists.txt | 55 ++++++++-------- .../cmake/gpu_param_header_generator.cmake | 65 ++++++++++--------- 4 files changed, 62 insertions(+), 62 deletions(-) diff --git a/GPU/GPUTracking/Base/cuda/CMakeLists.txt b/GPU/GPUTracking/Base/cuda/CMakeLists.txt index 27c3d24cd079f..6e54187332c9b 100644 --- a/GPU/GPUTracking/Base/cuda/CMakeLists.txt +++ b/GPU/GPUTracking/Base/cuda/CMakeLists.txt @@ -74,7 +74,7 @@ add_custom_command( COMMAND cat ${GPUDIR}/Base/GPUStdSystemHeaders.h >> ${GPU_RTC_BIN}.src COMMAND ${CMAKE_CUDA_COMPILER} ${GPU_RTC_DEFINES} ${GPU_RTC_INCLUDES} -std=c++${CMAKE_CUDA_STANDARD} -D__CUDA_ARCH__=${RTC_CUDA_ARCH} -Wno-deprecated-gpu-targets -D__CUDACC__ -x c++ -M -MD -MT ${GPU_RTC_BIN}.src -MF ${GPU_RTC_BIN}.src.d ${GPU_RTC_SRC} COMMAND ${CMAKE_CUDA_COMPILER} ${GPU_RTC_DEFINES} ${GPU_RTC_INCLUDES} -std=c++${CMAKE_CUDA_STANDARD} -D__CUDA_ARCH__=${RTC_CUDA_ARCH} -Wno-deprecated-gpu-targets -D__CUDACC__ -x c++ -E -Xcompiler "-nostdinc -P" ${GPU_RTC_SRC} >> ${GPU_RTC_BIN}.src - DEPENDS ${GPU_RTC_SRC} ${GPUDIR}/Base/GPUStdSystemHeaders.h ${GPUDIR}/Base/cuda/GPUReconstructionCUDAIncludesSystem.h ${GPUDIR}/Base/GPUStdSystemHeaders.h GPU_PARAM_HEADER_TARGET + DEPENDS ${GPU_RTC_SRC} ${GPUDIR}/Base/GPUStdSystemHeaders.h ${GPUDIR}/Base/cuda/GPUReconstructionCUDAIncludesSystem.h ${GPUDIR}/Base/GPUStdSystemHeaders.h DEPFILE ${GPU_RTC_BIN}.src.d COMMAND_EXPAND_LISTS COMMENT "Preparing CUDA RTC source file ${GPU_RTC_BIN}.src" diff --git a/GPU/GPUTracking/Base/hip/CMakeLists.txt b/GPU/GPUTracking/Base/hip/CMakeLists.txt index b459a78b5789e..50d710fd9d557 100644 --- a/GPU/GPUTracking/Base/hip/CMakeLists.txt +++ b/GPU/GPUTracking/Base/hip/CMakeLists.txt @@ -125,7 +125,7 @@ add_custom_command( COMMAND cat ${GPUDIR}/Base/hip/GPUReconstructionHIPIncludesSystem.h | grep -v GPUStdSystemHeaders.h >> ${GPU_RTC_BIN}.src COMMAND cat ${GPUDIR}/Base/GPUStdSystemHeaders.h >> ${GPU_RTC_BIN}.src COMMAND ${CMAKE_HIP_COMPILER} ${GPU_RTC_DEFINES} ${GPU_RTC_INCLUDES} -std=c++${CMAKE_HIP_STANDARD} -D__HIPCC__ -D__HIP_DEVICE_COMPILE__ -x c++ -nostdinc -E -P ${GPU_RTC_SRC} -MD -MT ${GPU_RTC_BIN}.src -MF ${GPU_RTC_BIN}.src.d >> ${GPU_RTC_BIN}.src - DEPENDS ${GPU_RTC_SRC} ${GPUDIR}/Base/GPUStdSystemHeaders.h ${GPUDIR}/Base/hip/GPUReconstructionHIPIncludesSystem.h ${GPUDIR}/Base/GPUStdSystemHeaders.h ${MODULE}_HIPIFIED GPU_PARAM_HEADER_TARGET + DEPENDS ${GPU_RTC_SRC} ${GPUDIR}/Base/GPUStdSystemHeaders.h ${GPUDIR}/Base/hip/GPUReconstructionHIPIncludesSystem.h ${GPUDIR}/Base/GPUStdSystemHeaders.h ${MODULE}_HIPIFIED DEPFILE ${GPU_RTC_BIN}.src.d COMMAND_EXPAND_LISTS COMMENT "Preparing HIP RTC source file ${GPU_RTC_BIN}.src" diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index 786774c16971b..e52fb80113c00 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -107,32 +107,6 @@ set(SRCS_NO_H SectorTracker/GPUTPCTrackerDump.cxx Global/GPUChainTrackingDebugAndProfiling.cxx Global/GPUChainTrackingIO.cxx) -if(GPUCA_OVERRIDE_PARAMETER_FILE) - set(GPU_PARAM_JSON ${GPUCA_OVERRIDE_PARAMETER_FILE}) -else() - set(GPU_PARAM_JSON ${CMAKE_CURRENT_SOURCE_DIR}/Definitions/Parameters/GPUParameters.csv) -endif() -set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${GPU_PARAM_JSON}") - -get_filename_component(GPU_PARAM_JSON_EXT ${GPU_PARAM_JSON} EXT) -string(TOLOWER "${GPU_PARAM_JSON_EXT}" GPU_PARAM_JSON_EXT) -if(GPU_PARAM_JSON_EXT STREQUAL .csv) - execute_process( - COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/Definitions/Parameters/csv_to_json.sh "${GPU_PARAM_JSON}" - OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/gpu_parameters.json - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - ) - message(STATUS "Converted ${GPU_PARAM_JSON} to ${CMAKE_CURRENT_BINARY_DIR}/gpu_parameters.json") - set(GPU_PARAM_JSON ${CMAKE_CURRENT_BINARY_DIR}/gpu_parameters.json) -endif() - -set(ON_THE_FLY_DIR ${CMAKE_CURRENT_BINARY_DIR}/include_gpu_onthefly) -file(MAKE_DIRECTORY ${ON_THE_FLY_DIR}) -include(cmake/gpu_param_header_generator.cmake) -set(GPU_DEFAULT_PARAMS_HEADER ${ON_THE_FLY_DIR}/GPUDefParametersDefaults.h) -set(GPU_DEFAULT_PARAMS_HEADER_DEVICE ${ON_THE_FLY_DIR}/GPUDefParametersDefaultsDevice.h) -generate_gpu_param_header("ALL" ${GPU_DEFAULT_PARAMS_HEADER} ${GPU_DEFAULT_PARAMS_HEADER_DEVICE} GPU_CONST_PARAM_ARCHITECTUES) # generate header with default GPU parameters, arch selected by CMake variables - set(HDRS_INSTALL ${HDRS_CINT_O2} ${HDRS_CINT_DATATYPES} @@ -161,8 +135,6 @@ set(HDRS_INSTALL DataTypes/GPUO2ExternalUser.h Debug/GPUROOTDump.h Definitions/GPUDefConstantsAndSettings.h - ${GPU_DEFAULT_PARAMS_HEADER} - ${GPU_DEFAULT_PARAMS_HEADER_DEVICE} Definitions/GPUDefParametersWrapper.h Definitions/GPUDefParametersConstants.h Definitions/GPUDef.h @@ -258,6 +230,8 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2") DataTypes/GPUO2ConfigurableParam.cxx) endif() +set(ON_THE_FLY_DIR ${CMAKE_CURRENT_BINARY_DIR}/include_gpu_onthefly) +file(MAKE_DIRECTORY ${ON_THE_FLY_DIR}) set(TEMPLATE_HEADER_LIST Base/GPUReconstructionKernelList.template.h Base/GPUReconstructionKernelIncludes.template.h Base/GPUReconstructionIncludesDeviceAll.template.h @@ -288,6 +262,31 @@ add_custom_command( ) list(APPEND GENERATED_HEADERS_LIST ${ON_THE_FLY_DIR}/GPUDefParametersLoadPrepare.h) +if(GPUCA_OVERRIDE_PARAMETER_FILE) + set(GPU_PARAM_JSON ${GPUCA_OVERRIDE_PARAMETER_FILE}) +else() + set(GPU_PARAM_JSON ${CMAKE_CURRENT_SOURCE_DIR}/Definitions/Parameters/GPUParameters.csv) +endif() +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${GPU_PARAM_JSON}") + +get_filename_component(GPU_PARAM_JSON_EXT ${GPU_PARAM_JSON} EXT) +string(TOLOWER "${GPU_PARAM_JSON_EXT}" GPU_PARAM_JSON_EXT) +if(GPU_PARAM_JSON_EXT STREQUAL .csv) + execute_process( + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/Definitions/Parameters/csv_to_json.sh "${GPU_PARAM_JSON}" + OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/gpu_parameters.json + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) + message(STATUS "Converted ${GPU_PARAM_JSON} to ${CMAKE_CURRENT_BINARY_DIR}/gpu_parameters.json") + set(GPU_PARAM_JSON ${CMAKE_CURRENT_BINARY_DIR}/gpu_parameters.json) +endif() + +include(cmake/gpu_param_header_generator.cmake) +set(GPU_DEFAULT_PARAMS_HEADER ${ON_THE_FLY_DIR}/GPUDefParametersDefaults.h) +set(GPU_DEFAULT_PARAMS_HEADER_DEVICE ${ON_THE_FLY_DIR}/GPUDefParametersDefaultsDevice.h) +generate_gpu_param_header("ALL" ${GPU_DEFAULT_PARAMS_HEADER} ${GPU_DEFAULT_PARAMS_HEADER_DEVICE} GPU_CONST_PARAM_ARCHITECTUES) # generate header with default GPU parameters, arch selected by CMake variables +list(APPEND GENERATED_HEADERS_LIST ${GPU_DEFAULT_PARAMS_HEADER} ${GPU_DEFAULT_PARAMS_HEADER_DEVICE}) + set(HDRS_INSTALL ${HDRS_INSTALL} ${GENERATED_HEADERS_LIST}) include(kernels.cmake) diff --git a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake index 31d395615a5ed..0a7b234aa6a18 100644 --- a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake +++ b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake @@ -38,42 +38,44 @@ function(generate_gpu_param_header ARCH_LIST OUT_HEADER OUT_HEADER_DEVICE) foreach(i RANGE 0 ${last}) string(JSON param_name MEMBER "${JSON_CONTENT}" "${TYPE}" "${i}") string(JSON n_archs LENGTH "${JSON_CONTENT}" "${TYPE}" "${param_name}") + if(n_archs GREATER 0) math(EXPR last_arch "${n_archs} - 1") - foreach(iArch RANGE 0 ${last_arch}) - string(JSON arch MEMBER "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${iArch}") - if(arch STREQUAL "default_cpu" AND NOT TYPE STREQUAL "PAR") - message(FATAL_ERROR "Bogus entry ${param_name} for ${arch}") - endif() - if(do_all_architectures GREATER -1) - if(NOT arch MATCHES ^default) - list(APPEND JSON_ARCHITECTURES "${arch}") + foreach(iArch RANGE 0 ${last_arch}) + string(JSON arch MEMBER "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${iArch}") + if(arch STREQUAL "default_cpu" AND NOT TYPE STREQUAL "PAR") + message(FATAL_ERROR "Bogus entry ${param_name} for ${arch}") endif() - set(list_idx 0) - else() - list(FIND ARCH_LIST_EXT "${arch}" list_idx) - endif() - if(list_idx GREATER -1) - string(JSON param_values GET "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${arch}") - if(TYPE STREQUAL "LB") - set(MACRO_NAME "GPUCA_LB_${param_name}") - elseif(TYPE STREQUAL "PAR") - set(MACRO_NAME "GPUCA_PAR_${param_name}") + if(do_all_architectures GREATER -1) + if(NOT arch MATCHES ^default) + list(APPEND JSON_ARCHITECTURES "${arch}") + endif() + set(list_idx 0) else() - set(MACRO_NAME "GPUCA_${param_name}") + list(FIND ARCH_LIST_EXT "${arch}" list_idx) endif() - set(vals "${param_values}") - string(REGEX REPLACE "^\\[ *" "" vals "${vals}") - string(REGEX REPLACE " *\\]$" "" vals "${vals}") - string(REGEX REPLACE "\"" "" vals "${vals}") - set(MACRO_DEFINITION "#define ${MACRO_NAME} ${vals}") - if(arch MATCHES ^default) - # fallback defaults are wrapped in #ifndef - string(APPEND generate_gpu_param_header_OUTPUT_TMP_${arch} "#ifndef ${MACRO_NAME}\n ${MACRO_DEFINITION}\n#endif\n\n") - else() - string(APPEND generate_gpu_param_header_OUTPUT_TMP_${arch} "${MACRO_DEFINITION}\n") + if(list_idx GREATER -1) + string(JSON param_values GET "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${arch}") + if(TYPE STREQUAL "LB") + set(MACRO_NAME "GPUCA_LB_${param_name}") + elseif(TYPE STREQUAL "PAR") + set(MACRO_NAME "GPUCA_PAR_${param_name}") + else() + set(MACRO_NAME "GPUCA_${param_name}") + endif() + set(vals "${param_values}") + string(REGEX REPLACE "^\\[ *" "" vals "${vals}") + string(REGEX REPLACE " *\\]$" "" vals "${vals}") + string(REGEX REPLACE "\"" "" vals "${vals}") + set(MACRO_DEFINITION "#define ${MACRO_NAME} ${vals}") + if(arch MATCHES ^default) + # fallback defaults are wrapped in #ifndef + string(APPEND generate_gpu_param_header_OUTPUT_TMP_${arch} "#ifndef ${MACRO_NAME}\n ${MACRO_DEFINITION}\n#endif\n\n") + else() + string(APPEND generate_gpu_param_header_OUTPUT_TMP_${arch} "${MACRO_DEFINITION}\n") + endif() endif() - endif() - endforeach() + endforeach() + endif() endforeach() endforeach() @@ -121,5 +123,4 @@ function(generate_gpu_param_header ARCH_LIST OUT_HEADER OUT_HEADER_DEVICE) file(GENERATE OUTPUT "${OUT_HEADER}" CONTENT "${TMP_HEADER}") file(GENERATE OUTPUT "${OUT_HEADER_DEVICE}" CONTENT "${TMP_HEADER_DEVICE}") message(STATUS "Generated ${OUT_HEADER} and ${OUT_HEADER_DEVICE}") - add_custom_target(GPU_PARAM_HEADER_TARGET ALL DEPENDS ${OUT_HEADER} ${OUT_HEADER_DEVICE} ${GPU_PARAM_JSON}) endfunction() From f1175e1181e24441768ca3f97655786fcadee539 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 9 Feb 2026 00:03:02 +0100 Subject: [PATCH 168/234] GPU Parameters: Support multiple csv/json files, and merge the parameters into the header on the fly --- GPU/GPUTracking/CMakeLists.txt | 37 +++++--- .../cmake/gpu_param_header_generator.cmake | 95 ++++++++++--------- 2 files changed, 75 insertions(+), 57 deletions(-) diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index e52fb80113c00..082dc1f10b1d6 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -263,28 +263,39 @@ add_custom_command( list(APPEND GENERATED_HEADERS_LIST ${ON_THE_FLY_DIR}/GPUDefParametersLoadPrepare.h) if(GPUCA_OVERRIDE_PARAMETER_FILE) - set(GPU_PARAM_JSON ${GPUCA_OVERRIDE_PARAMETER_FILE}) + set(GPU_PARAM_JSON ${GPUCA_OVERRIDE_PARAMETER_FILE}) else() - set(GPU_PARAM_JSON ${CMAKE_CURRENT_SOURCE_DIR}/Definitions/Parameters/GPUParameters.csv) + set(GPU_PARAM_JSON ${CMAKE_CURRENT_SOURCE_DIR}/Definitions/Parameters/GPUParameters.csv) endif() set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${GPU_PARAM_JSON}") -get_filename_component(GPU_PARAM_JSON_EXT ${GPU_PARAM_JSON} EXT) -string(TOLOWER "${GPU_PARAM_JSON_EXT}" GPU_PARAM_JSON_EXT) -if(GPU_PARAM_JSON_EXT STREQUAL .csv) - execute_process( - COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/Definitions/Parameters/csv_to_json.sh "${GPU_PARAM_JSON}" - OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/gpu_parameters.json - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +set(GPU_PARAM_JSON_FILES) +set(GPU_PARAM_JSON_N_FILES 0) +foreach(GPU_PARAM_JSON_FILE IN LISTS GPU_PARAM_JSON) + if(NOT EXISTS "${GPU_PARAM_JSON_FILE}") + message(FATAL_ERROR "Parameter file ${GPU_PARAM_JSON_FILE} does not exist") + endif() + get_filename_component(GPU_PARAM_JSON_EXT ${GPU_PARAM_JSON_FILE} EXT) + string(TOLOWER "${GPU_PARAM_JSON_EXT}" GPU_PARAM_JSON_EXT) + if(GPU_PARAM_JSON_EXT STREQUAL .csv) + get_filename_component(GPU_PARAM_JSON_NAME ${GPU_PARAM_JSON_FILE} NAME_WE) + set(CONVOUTFILE "GPUParameters_${GPU_PARAM_JSON_NAME}_${GPU_PARAM_JSON_N_FILES}.json") + execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/Definitions/Parameters/csv_to_json.sh "${GPU_PARAM_JSON_FILE}" + OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/${CONVOUTFILE} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) - message(STATUS "Converted ${GPU_PARAM_JSON} to ${CMAKE_CURRENT_BINARY_DIR}/gpu_parameters.json") - set(GPU_PARAM_JSON ${CMAKE_CURRENT_BINARY_DIR}/gpu_parameters.json) -endif() + message(STATUS "Converted ${GPU_PARAM_JSON_FILE} to ${CONVOUTFILE}") + list(APPEND GPU_PARAM_JSON_FILES ${CMAKE_CURRENT_BINARY_DIR}/${CONVOUTFILE}) + else() + list(APPEND GPU_PARAM_JSON_FILES ${GPU_PARAM_JSON_FILE}) + endif() + math(EXPR GPU_PARAM_JSON_N_FILES "${GPU_PARAM_JSON_N_FILES} + 1") +endforeach() include(cmake/gpu_param_header_generator.cmake) set(GPU_DEFAULT_PARAMS_HEADER ${ON_THE_FLY_DIR}/GPUDefParametersDefaults.h) set(GPU_DEFAULT_PARAMS_HEADER_DEVICE ${ON_THE_FLY_DIR}/GPUDefParametersDefaultsDevice.h) -generate_gpu_param_header("ALL" ${GPU_DEFAULT_PARAMS_HEADER} ${GPU_DEFAULT_PARAMS_HEADER_DEVICE} GPU_CONST_PARAM_ARCHITECTUES) # generate header with default GPU parameters, arch selected by CMake variables +generate_gpu_param_header("${GPU_PARAM_JSON_FILES}" "ALL" "${GPU_DEFAULT_PARAMS_HEADER}" "${GPU_DEFAULT_PARAMS_HEADER_DEVICE}" GPU_CONST_PARAM_ARCHITECTUES) # generate header with default GPU parameters, arch selected by CMake variables list(APPEND GENERATED_HEADERS_LIST ${GPU_DEFAULT_PARAMS_HEADER} ${GPU_DEFAULT_PARAMS_HEADER_DEVICE}) set(HDRS_INSTALL ${HDRS_INSTALL} ${GENERATED_HEADERS_LIST}) diff --git a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake index 0a7b234aa6a18..383d194aaa717 100644 --- a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake +++ b/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake @@ -12,7 +12,7 @@ # file gpu_param_header_generator.cmake # author Gabriele Cimador -function(generate_gpu_param_header ARCH_LIST OUT_HEADER OUT_HEADER_DEVICE) +function(generate_gpu_param_header GPU_PARAM_JSON_FILES ARCH_LIST OUT_HEADER OUT_HEADER_DEVICE) list(FIND ARCH_LIST "ALL" do_all_architectures) list(FIND ARCH_LIST "AUTO" do_auto_architectures) if(do_all_architectures GREATER -1 OR do_auto_architectures GREATER -1) @@ -24,7 +24,6 @@ function(generate_gpu_param_header ARCH_LIST OUT_HEADER OUT_HEADER_DEVICE) endif() list(APPEND ARCH_LIST ${TARGET_ARCH}) endif() - file(READ "${GPU_PARAM_JSON}" JSON_CONTENT) # Types set(TYPES CORE LB PAR) @@ -32,57 +31,65 @@ function(generate_gpu_param_header ARCH_LIST OUT_HEADER OUT_HEADER_DEVICE) # Per architecture definitions set(JSON_ARCHITECTURES) - foreach(TYPE IN LISTS TYPES) - string(JSON n_params LENGTH "${JSON_CONTENT}" "${TYPE}") - math(EXPR last "${n_params} - 1") - foreach(i RANGE 0 ${last}) - string(JSON param_name MEMBER "${JSON_CONTENT}" "${TYPE}" "${i}") - string(JSON n_archs LENGTH "${JSON_CONTENT}" "${TYPE}" "${param_name}") - if(n_archs GREATER 0) - math(EXPR last_arch "${n_archs} - 1") - foreach(iArch RANGE 0 ${last_arch}) - string(JSON arch MEMBER "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${iArch}") - if(arch STREQUAL "default_cpu" AND NOT TYPE STREQUAL "PAR") - message(FATAL_ERROR "Bogus entry ${param_name} for ${arch}") - endif() - if(do_all_architectures GREATER -1) - if(NOT arch MATCHES ^default) - list(APPEND JSON_ARCHITECTURES "${arch}") + set(GPU_PARAM_JSON_N_FILES 0) + foreach(GPU_PARAM_JSON_FILE IN LISTS GPU_PARAM_JSON_FILES) + file(READ "${GPU_PARAM_JSON_FILE}" JSON_CONTENT) + foreach(TYPE IN LISTS TYPES) + string(JSON n_params LENGTH "${JSON_CONTENT}" "${TYPE}") + math(EXPR last "${n_params} - 1") + foreach(i RANGE 0 ${last}) + string(JSON param_name MEMBER "${JSON_CONTENT}" "${TYPE}" "${i}") + string(JSON n_archs LENGTH "${JSON_CONTENT}" "${TYPE}" "${param_name}") + if(n_archs GREATER 0) + math(EXPR last_arch "${n_archs} - 1") + foreach(iArch RANGE 0 ${last_arch}) + string(JSON arch MEMBER "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${iArch}") + if(arch STREQUAL "default_cpu" AND NOT TYPE STREQUAL "PAR") + message(FATAL_ERROR "Bogus entry ${param_name} for ${arch}") endif() - set(list_idx 0) - else() - list(FIND ARCH_LIST_EXT "${arch}" list_idx) - endif() - if(list_idx GREATER -1) - string(JSON param_values GET "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${arch}") - if(TYPE STREQUAL "LB") - set(MACRO_NAME "GPUCA_LB_${param_name}") - elseif(TYPE STREQUAL "PAR") - set(MACRO_NAME "GPUCA_PAR_${param_name}") - else() - set(MACRO_NAME "GPUCA_${param_name}") + if(arch MATCHES ^default AND GPU_PARAM_JSON_N_FILES GREATER 0) + message(FATAL_ERROR "Defaults must be provided in first parameter file") endif() - set(vals "${param_values}") - string(REGEX REPLACE "^\\[ *" "" vals "${vals}") - string(REGEX REPLACE " *\\]$" "" vals "${vals}") - string(REGEX REPLACE "\"" "" vals "${vals}") - set(MACRO_DEFINITION "#define ${MACRO_NAME} ${vals}") - if(arch MATCHES ^default) - # fallback defaults are wrapped in #ifndef - string(APPEND generate_gpu_param_header_OUTPUT_TMP_${arch} "#ifndef ${MACRO_NAME}\n ${MACRO_DEFINITION}\n#endif\n\n") + if(do_all_architectures GREATER -1) + if(NOT arch MATCHES ^default) + list(APPEND JSON_ARCHITECTURES "${arch}") + endif() + set(list_idx 0) else() - string(APPEND generate_gpu_param_header_OUTPUT_TMP_${arch} "${MACRO_DEFINITION}\n") + list(FIND ARCH_LIST_EXT "${arch}" list_idx) + endif() + if(list_idx GREATER -1) + string(JSON param_values GET "${JSON_CONTENT}" "${TYPE}" "${param_name}" "${arch}") + if(TYPE STREQUAL "LB") + set(MACRO_NAME "GPUCA_LB_${param_name}") + elseif(TYPE STREQUAL "PAR") + set(MACRO_NAME "GPUCA_PAR_${param_name}") + else() + set(MACRO_NAME "GPUCA_${param_name}") + endif() + set(vals "${param_values}") + string(REGEX REPLACE "^\\[ *" "" vals "${vals}") + string(REGEX REPLACE " *\\]$" "" vals "${vals}") + string(REGEX REPLACE "\"" "" vals "${vals}") + set(MACRO_DEFINITION "#define ${MACRO_NAME} ${vals}") + if(arch MATCHES ^default) + # fallback defaults are wrapped in #ifndef + string(APPEND generate_gpu_param_header_OUTPUT_TMP_${arch} "#ifndef ${MACRO_NAME}\n ${MACRO_DEFINITION}\n#endif\n\n") + else() + string(APPEND generate_gpu_param_header_OUTPUT_TMP_${arch} "${MACRO_DEFINITION}\n") + endif() endif() - endif() - endforeach() - endif() + endforeach() + endif() + endforeach() endforeach() + math(EXPR GPU_PARAM_JSON_N_FILES "${GPU_PARAM_JSON_N_FILES} + 1") endforeach() list(REMOVE_DUPLICATES JSON_ARCHITECTURES) list(SORT JSON_ARCHITECTURES) - if(ARGC GREATER 3) - set(${ARGV3} "${JSON_ARCHITECTURES}" PARENT_SCOPE) + if(ARGC GREATER 4) + set(${ARGV4} "${JSON_ARCHITECTURES}" PARENT_SCOPE) endif() if(do_all_architectures GREATER -1) list(REMOVE_ITEM ARCH_LIST "ALL") From b77438bbd5aa8d07b4458b5eb80bf519ba9f6ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ku=C4=8Dera?= <26327373+vkucera@users.noreply.github.com> Date: Mon, 9 Feb 2026 09:25:15 +0100 Subject: [PATCH 169/234] Utilities: Delete unused files (#15039) --- .../DataCompression/CodingModelDispatcher.h | 380 ------------ .../DataCompression/runtime_container.h | 583 ------------------ .../tpccluster_parameter_model.h | 101 --- .../internal/containers/HistogramInterface.h | 88 --- 4 files changed, 1152 deletions(-) delete mode 100644 Utilities/DataCompression/include/DataCompression/CodingModelDispatcher.h delete mode 100644 Utilities/DataCompression/include/DataCompression/runtime_container.h delete mode 100644 Utilities/DataCompression/tpccluster_parameter_model.h delete mode 100644 Utilities/rANS/include/rANS/internal/containers/HistogramInterface.h diff --git a/Utilities/DataCompression/include/DataCompression/CodingModelDispatcher.h b/Utilities/DataCompression/include/DataCompression/CodingModelDispatcher.h deleted file mode 100644 index 68fcc8360df2b..0000000000000 --- a/Utilities/DataCompression/include/DataCompression/CodingModelDispatcher.h +++ /dev/null @@ -1,380 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/* Local Variables: */ -/* mode: c++ */ -/* End: */ - -#ifndef CODINGMODELDISPATCHER_H -#define CODINGMODELDISPATCHER_H - -/// @file CodingModelDispatcher.h -/// @author Matthias Richter -/// @since 2016-09-11 -/// @brief Runtime dispatcher interface for probability model definitions - -#include "mpl_tools.h" -#include "runtime_container.h" -#include -#include -#include -#include - -using namespace gNeric; - -namespace o2 -{ -namespace data_compression -{ - -/** - * @class CodingModelDispatcher Runtime dispatcher interface - * @brief Runtime dispatcher interface for probability model definitions - * - * ModelDefinition single coding model or mpl sequence of models - * - * TODO: - * - consistency check for coding direction, all model definitions have to obey - * same direction - * - probably one should also require the same code type for all definitions, at - * least in the codec. Multiple code types do not make much sense in the codec - */ -template -class CodingModelDispatcher -{ - public: - CodingModelDispatcher() : mPosition(0), mContainer() {} - ~CodingModelDispatcher() = default; - - using self_type = CodingModelDispatcher; - - // make_mpl_vector traits makes sure that an mpl sequence is used further on - // if the original type is not a sequence it is wrapped into an mpl vector with - // the original type as the only element - using definition_type = typename mpl::make_mpl_vector::type; - - // the runtime container type is the heart of the dispatcher to runtime objects - // of the sequence of data types which define the probability model - using container_type = typename create_rtc>::type; - - using code_type = typename container_type::wrapped_type::code_type; - - /// get the number of models in the definition - static int getNumberOfModels() { return boost::mpl::size::value; } - - /// return highest stage of runtime container - container_type& operator*() { return mContainer; } - - /// functor to add weight to probability model at runtime container level - template - class addWeightFctr - { - public: - addWeightFctr(ValueType _v, WeightType _w) : value(_v), weight(_w) {} - ~addWeightFctr() {} - - using return_type = bool; - - template - return_type operator()(T& stage) - { - // the addWeight function belongs to the probability model as base - // of the specific model; funcions of the base can be accessed by - // static casting. This avoids an extra level of function calls. - return static_cast(*stage).addWeight(value, weight); - } - - private: - ValueType value; - WeightType weight; - }; - - /** - * add weight to current model - * - * Dispatcher increments to the next model definition after decoding if - * parameter switchToNextModel is true. - */ - template - bool addWeight(ValueType v, WeightType w, bool switchToNextModel = true) - { - bool result = mContainer.apply(mPosition, addWeightFctr(v, w)); - if (switchToNextModel && ++mPosition >= getNumberOfModels()) { - mPosition = 0; - } - return result; - } - - /** - * init model - */ - class initFctr - { - public: - initFctr(container_type& container) : mContainer(container) {} - ~initFctr() {} - - using return_type = int; - - template - return_type operator()(boost::type) - { - T& stage = static_cast(mContainer); - return (*stage).init(); - } - - private: - container_type& mContainer; - }; - - /** - * init dispatcher and models - */ - int init() - { - mPosition = 0; - boost::mpl::for_each>(initFctr(mContainer)); - return 0; - } - - /** - * TODO: this is tailored to HuffmanCodec for the moment, some generic interface - * has to come - */ - class generateFctr - { - public: - generateFctr(container_type& container) : mContainer(container) {} - ~generateFctr() {} - - using return_type = int; - - template - return_type operator()(boost::type) - { - T& stage = static_cast(mContainer); - return (*stage).GenerateHuffmanTree(); - } - - private: - container_type& mContainer; - }; - - /** - * TODO: maybe 'generate' is not the appropriate name - */ - int generate() - { - boost::mpl::for_each>(generateFctr(mContainer)); - return 0; - } - - /// functor to execute encoding on runtime container level - template - class encodeFctr - { - public: - encodeFctr(ValueType _v, CodeType& _code, uint16_t& _codeLength) : code(_code), value(_v), codeLength(_codeLength) - { - } - ~encodeFctr() {} - - using return_type = bool; - - template - return_type operator()(T& stage) - { - code = (*stage).Encode(value, codeLength); - return true; - } - - private: - CodeType& code; - ValueType value; - uint16_t& codeLength; - }; - - /** - * Encode a value - * - * Dispatcher increments to the next model definition after decoding if - * parameter switchToNextModel is true. - */ - template - bool encode(ValueType v, CodeType& code, uint16_t& codeLength, bool switchToNextModel = true) - { - bool result = mContainer.apply(mPosition, encodeFctr(v, code, codeLength)); - if (switchToNextModel && ++mPosition >= getNumberOfModels()) { - mPosition = 0; - } - return result; - } - - /// Functor to execute decoding on runtime container level - template - class decodeFctr - { - public: - decodeFctr(ValueType& _v, CodeType _code, uint16_t& _codeLength) : code(_code), value(_v), codeLength(_codeLength) - { - } - ~decodeFctr() {} - - using return_type = bool; - - template - return_type operator()(T& stage) - { - value = (*stage).Decode(code, codeLength); - return true; - } - - private: - CodeType code; - ValueType& value; - uint16_t& codeLength; - }; - - /** - * Decode a code sequence - * Code direction can be either from MSB to LSB or LSB to MSB, controlled - * by template parameter orderMSB of the probability model. - * - * Dispatcher increments to the next model definition after decoding if - * parameter switchToNextModel is true. - */ - template - bool decode(ValueType& v, CodeType code, uint16_t& codeLength, bool switchToNextModel = true) - { - bool result = mContainer.apply(mPosition, decodeFctr(v, code, codeLength)); - if (switchToNextModel && ++mPosition >= getNumberOfModels()) { - mPosition = 0; - } - return result; - } - - class getCodingDirectionFctr - { - public: - using return_type = bool; - template - return_type operator()(T& stage) - { - return T::wrapped_type::orderMSB; - } - }; - - /** - * Get coding direction for model at current position - */ - bool getCodingDirection() { return mContainer.apply(mPosition, getCodingDirectionFctr()); } - - /// write functor - class writeFctr - { - public: - writeFctr(std::ostream& out, container_type& container) : mOut(out), mContainer(container) {} - ~writeFctr() {} - - using return_type = std::ostream&; - - template - return_type operator()(boost::type) - { - T& stage = static_cast(mContainer); - if (T::level::value > 0) { - mOut << std::endl; // blank line between dumps - } - mOut << T::level::value << " " << (*stage).getName() << std::endl; - (*stage).write(mOut); - return mOut; - } - - private: - std::ostream& mOut; - container_type& mContainer; - }; - - /** - * Write configuration - * - * TODO: introduce a general storage policy, a text file is used for now - */ - int write(const char* filename = nullptr) - { - std::ofstream ofile(filename); - boost::mpl::for_each>( - writeFctr(ofile.good() ? ofile : std::cout, mContainer)); - ofile.close(); - return 0; - } - - /// read functor - class readFctr - { - public: - readFctr(std::istream& in, container_type& container) : mIn(in), mContainer(container) {} - ~readFctr() {} - - using return_type = bool; - - template - return_type operator()(boost::type) - { - T& stage = static_cast(mContainer); - std::string level, name, remaining; - mIn >> level; - mIn >> name; - if (!mIn) { - return false; - } - if (std::stoi(level) != T::level::value || name.compare((*stage).getName())) { - std::cerr << "Format error: expecting level '" << T::level::value << "' and name '" << (*stage).getName() - << "', got: " << level << " " << name << std::endl; - } - std::cout << "reading configuration for model " << name << std::endl; - std::getline(mIn, remaining); // flush the current line - (*stage).read(mIn); - return true; - } - - private: - std::istream& mIn; - container_type& mContainer; - }; - - /** - * Read configuration - * - * TODO: introduce a general storage policy, a text file is used for now - */ - int read(const char* filename) - { - std::ifstream input(filename); - if (!input.good()) { - return -1; - } - // TODO: probably need mpl fold here to propagate the return value - boost::mpl::for_each>(readFctr(input, mContainer)); - return 0; - } - - private: - /// position for cyclic dispatch - int mPosition; - /// the runtime container - container_type mContainer; -}; - -} // namespace data_compression -} // namespace o2 - -#endif diff --git a/Utilities/DataCompression/include/DataCompression/runtime_container.h b/Utilities/DataCompression/include/DataCompression/runtime_container.h deleted file mode 100644 index 363f4220e73f6..0000000000000 --- a/Utilities/DataCompression/include/DataCompression/runtime_container.h +++ /dev/null @@ -1,583 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -//-*- Mode: C++ -*- - -#ifndef RUNTIME_CONTAINER_H -#define RUNTIME_CONTAINER_H -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Author(s): Matthias Richter * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//**************************************************************************** - -/// @file runtime_container.h -/// @author Matthias Richter -/// @since 2016-09-11 -/// @brief A general runtime container for a compile time sequence -/// This file is part of https://github.com/matthiasrichter/gNeric - -// clang-format off - -// A general runtime container for a compile time sequence -// of types. A mixin class is used to represent a member of each data -// type. Every data type in the sequence describes a mixin on top of -// the previous one. The runtime container accumulates the type -// properties. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace boost::mpl::placeholders; - -namespace gNeric { - -/** - * @class DefaultInterface - * @brief The default interface for the RuntimeContainer - * - * The common interface for the mixin class. In order to allow entry - * points to the different levels of the mixin, none of the interface - * functions has to be declared virtual. The function implementation of - * the top most mixin would be called otherwise. - * - * The mixin technique requires a base class, but it mostly makes sense in - * the picture of runtime polymorphism and virtual interfaces. The runtime - * container application is purely using static polymorphism which makes the - * base interface just to a technical aspect. - */ -class DefaultInterface -{ -public: - DefaultInterface() {} - ~DefaultInterface() {} - - void print() const {} -}; - -/** - * @brief Default initializer does nothing - */ -struct default_initializer -{ - template - void operator()(T&) {} -}; - -/** - * @brief An initializer for simple types - * The initializer makes use of truncation for non-float types, and - * over- and underflow to produce different values in the member - * of the individual stages in the container. - * - float types keep the fraction - * - integral types truncate the fraction - * - unsigned types undergo an underflow and produce big numbers - * - 8 bit char produces the '*' character - * - * Mainly for testing and illustration purposes. - */ -struct funny_initializer -{ - template - void operator()(T& v) {v=0; v-=214.5;} -}; - -/** - * @brief Default printer prints nothing - */ -struct default_printer -{ - template - bool operator()(const T& v, int level = -1) {return false;} -}; - -/** - * @brief Verbose printer prints level and content - */ -template -struct verbose_printer_base -{ - template - bool operator()(const T& v, int level = -1) { - std::cout << "RC mixin level " - << std::setw(2) - << level << ": " << v << std::endl; - return recursive; - } -}; - -/** - * @brief Verbose printer to print levels recursively - */ -struct recursive_printer : verbose_printer_base {}; - -// preserve backward compatibility -typedef recursive_printer verbose_printer; - -/** - * @brief Verbose printer to print a single level - */ -struct single_printer : verbose_printer_base {}; - -/** - * @brief Setter functor, forwards to the container mixin's set function - */ -template -class set_value { -public: - typedef void return_type; - typedef U value_type; - - set_value(U u) : mValue(u) {} - template - return_type operator()(T& t) { - *t = mValue; - } - -private: - set_value(); // forbidden - U mValue; -}; - -/** - * @brief Adder functor - */ -template -class add_value { -public: - typedef void return_type; - typedef U value_type; - - add_value(U u) : mValue(u) {} - template - return_type operator()(T& t) { - *t += mValue; - } - -private: - add_value(); // forbidden - U mValue; -}; - -/** - * @brief Getter functor, forwards to the container mixin's get function - * - * TODO: make a type trait to either return t.get() if its a container - * instance or t directly if it is the member object - */ -template -class get_value { -public: - typedef U return_type; - typedef U value_type; - class NullType {}; -private: - /* could not solve the problem that one has to instantiate Traits - with a fixed number of template arguments where wrapped_type - would need to be provided already to go into the specialization - template - struct Traits { - typedef NullType container_type; - typedef InstanceType type; - static return_type apply(InstanceType& c) { - std::cout << "Traits"; - return c; - } - }; - // specialization for container instances - template - struct Traits { - typedef InstanceType container_type; - typedef typename InstanceType::wrapped_type type; - static return_type apply(InstanceType& c) { - std::cout << "specialized Traits"; - return c.get(); - } - }; - */ - -public: - template - return_type operator()(T& t) { - return t.get(); - //return (typename Traits::type)(t); - } -}; - - -/****************************************************************************** - * @brief apply functor to the wrapped member object in the runtime container - * This meta function recurses through the list while incrementing the index - * and calls the functor at the required position - * - * @note internal meta function for the RuntimeContainers' apply function - */ -template < - typename _ContainerT // container type - , typename _IndexT // data type of position index - , typename _Iterator // current iterator position - , typename _End // end iterator position - , _IndexT _Index // current index - , typename F // functor - > -struct rc_apply_at -{ - static typename F::return_type apply( _ContainerT& c, _IndexT position, F& f ) - { - if ( position == _Index ) { - // this is the queried position, make the type cast to the current - // stage of the runtime container and execute function for it. - // Terminate loop by forwarding _End as _Iterator and thus - // calling the specialization - typedef typename boost::mpl::deref< _Iterator >::type stagetype; - stagetype& stage = static_cast(c); - return f(stage); - } else { - // go to next element - return rc_apply_at< - _ContainerT - , _IndexT - , typename boost::mpl::next< _Iterator >::type - , _End - , _Index + 1 - , F - >::apply( c, position, f ); - } - } -}; -// specialization: end of recursive loop, kicks in if _Iterator matches -// _End. -// here we end up if the position parameter is out of bounds -template < - typename _ContainerT // container type - , typename _IndexT // data type of position index - , typename _End // end iterator position - , _IndexT _Index // current index - , typename F // functor - > -struct rc_apply_at<_ContainerT - , _IndexT - , _End - , _End - , _Index - , F - > -{ - static typename F::return_type apply( _ContainerT& c, _IndexT position, F& f ) - { - // TODO: this is probably the place to throw an exeption because - // we are out of bound - return typename F::return_type(0); - } -}; - -/** - * Apply functor to the specified container level - * - * Ignores parameter '_IndexT' - */ -template -struct rc_apply { - typedef typename _ContainerT::types types; - static typename F::return_type apply(_ContainerT& c, _IndexT /*ignored*/, F& f) - { - return f(static_cast<_StageT&>(c)); - } -}; - -/** - * Generalized dispatcher with the ability for code unrolling - * - * The optional template parameter 'Position' can be used to cast directly to - * the specified level in the runtime container and apply the functor without - * the recursive loop. The template call with default parameters forwards to - * the recursive call because 'Position' is set to out of list range. - */ -template - , typename _IndexT = int - > -struct rc_dispatcher { - typedef typename _ContainerT::types types; - typedef typename boost::mpl::if_< - boost::mpl::less > - , rc_apply<_ContainerT, typename boost::mpl::at::type, _IndexT, F> - , rc_apply_at< - _ContainerT - , _IndexT - , typename boost::mpl::begin::type - , typename boost::mpl::end::type - , 0 - , F - > - >::type type; - - static typename F::return_type apply(_ContainerT& c, _IndexT position, F& f) { - return type::apply(c, position, f); - } -}; - -/** - * @class RuntimeContainer The base for the mixin class - * @brief the technical base of the mixin class - * - * The class is necessary to provide the innermost functionality of the - * mixin. - * - * The level of the mixin is encoded in the type 'level' which is - * incremented in each mixin stage. - */ -template -struct RuntimeContainer : public InterfacePolicy -{ - InitializerPolicy _initializer; - PrinterPolicy _printer; - typedef boost::mpl::int_<-1> level; - typedef boost::mpl::vector<>::type types; - - /// get size which is 0 at this level - constexpr std::size_t size() const {return 0;} - - void print() { - const char* string = "base"; - _printer(string, level::value); - } - - // not yet clear if we need the setter and getter in the base class - // at least wrapped_type is not defined in the base - //void set(wrapped_type) {mMember = v;} - //wrapped_type get() const {return mMember;} - -}; - -/** - * @class rc_mixin Components for the mixin class - * @brief Mixin component is used with different data types - * - * Each mixin component has a member of the specified type. The container - * level exports the following data types to the outside: - * - wrapped_type the data type at this level - * - mixin_type composed type at this level - * - types mpl sequence containing all level types - * - level a data type containing the level - */ -template -class rc_mixin : public BASE -{ -public: - rc_mixin() : mMember() {BASE::_initializer(mMember);} - - /// each stage of the mixin class wraps one type - typedef T wrapped_type; - /// this is the self type - typedef rc_mixin mixin_type; - /// a vector of all mixin stage types so far - typedef typename boost::mpl::push_back::type types; - /// increment the level counter - typedef typename boost::mpl::plus< typename BASE::level, boost::mpl::int_<1> >::type level; - void print() { - // use the printer policy of this level, the policy returns - // a bool determining whether to call the underlying level - if (BASE::_printer(mMember, level::value)) { - BASE::print(); - } - } - - /// get size at this stage - constexpr std::size_t size() const {return level::value + 1;} - /// set member wrapped object - void set(wrapped_type v) {mMember = v;} - /// get wrapped object - wrapped_type get() const {return mMember;} - /// get wrapped object reference - wrapped_type& operator*() {return mMember;} - /// assignment operator to wrapped type - wrapped_type& operator=(const wrapped_type& v) {mMember = v; return mMember;} - /// type conversion to wrapped type - operator wrapped_type() const {return mMember;} - /// operator - wrapped_type& operator+=(const wrapped_type& v) {mMember += v; return mMember;} - /// operator - wrapped_type operator+(const wrapped_type& v) {return mMember + v;} - - /// a functor wrapper dereferencing the RC container instance - /// the idea is to use this extra wrapper to apply the functor directly to - /// the wrapped type, see the comment below - template - class member_apply_at { - public: - member_apply_at(F& f) : mFunctor(f) {} - typedef typename F::return_type return_type; - template - typename F::return_type operator()(_T& me) { - return mFunctor(*me); - } - private: - member_apply_at(); //forbidden - F& mFunctor; - }; - - /// apply functor to the runtime object at index - /// TODO: there is a performance issue with this solution, introducing another - /// level of functors makes the access much slower compared with applying to - /// container instance and using container member functions, tested with the - /// add_value functor and bench_runtime_container, also the actual operation - /// needs to be checked, the result is not correct for the last check of - /// 100000000 iterations - /* - template - typename F::return_type applyToMember(int index, F f) { - return apply(index, member_apply_at(f)); - } - */ - - /* - * Apply a functor to the runtime container at index - * - * For performance tests there is a template option to do an explicite loop - * unrolling for the first n (=10) elements. This is however only effective - * if the compiler optimization is switched of. This is in the end a nice - * demonstrator for the potential of compiler optimization. Unrolling is - * switched on with the compile time switch RC_UNROLL. - */ - template - typename F::return_type apply(int index, F f) { - if (unroll) {// this is a compile time switch - // do unrolling for the first n elements and forward to generic - // recursive function for the rest. - switch (index) { - case 0: return rc_dispatcher, int>::apply(*this, 0, f); - case 1: return rc_dispatcher, int>::apply(*this, 1, f); - case 2: return rc_dispatcher, int>::apply(*this, 2, f); - case 3: return rc_dispatcher, int>::apply(*this, 3, f); - case 4: return rc_dispatcher, int>::apply(*this, 4, f); - case 5: return rc_dispatcher, int>::apply(*this, 5, f); - case 6: return rc_dispatcher, int>::apply(*this, 6, f); - case 7: return rc_dispatcher, int>::apply(*this, 7, f); - case 8: return rc_dispatcher, int>::apply(*this, 8, f); - case 9: return rc_dispatcher, int>::apply(*this, 9, f); - } - } - return rc_dispatcher::apply(*this, index, f); - } - -private: - T mMember; -}; - -/** - * @brief Applying rc_mixin with the template parameters as placeholders - * The wrapping into an mpl lambda is necessary to separate placeholder scopes - * in the mpl fold operation. - */ -typedef typename boost::mpl::lambda< rc_mixin<_1, _2> >::type apply_rc_mixin; - -/** - * @brief check the mixin level to be below specified level - * - * @note: the number is specified as a type, e.g. boost::mpl:int_<3> - */ -template< typename T, typename N > struct rtc_less -: boost::mpl::bool_<(T::level::value < boost::mpl::minus>::value) > {}; - -template< typename T, typename N > struct rtc_equal -: boost::mpl::bool_::type> {}; - -/** - * @brief create the runtime container type - * The runtime container type is build from a list of data types, the recursive - * build can be optionally stopped at the level of argument N. - * - * Usage: typedef create_rtc::type container_type; - */ -template> -struct create_rtc -{ - typedef typename boost::mpl::lambda< - // mpl fold loops over all elements in the list of the first template - // parameter and provides this as placeholder _2; for every element the - // operation of the third template parameter is applied to the result of - // the previous stage which is provided as placeholder _1 to the operation - // and initialized to the second template argument for the very first - // operation - typename boost::mpl::fold< - // list of types, each element provided as placeholder _1 - Types - // initializer for the _1 placeholder - , Base - // recursively applied operation, depending on the outcome of rtc_less - // either the next mixin level is applied or the current state is used - , boost::mpl::if_< - rtc_less<_1, N > - // apply mixin level - , boost::mpl::apply2< boost::mpl::protect::type, _1, _2 > - // keep current state by identity - , boost::mpl::identity<_1> - > - >::type - >::type type; -}; - -/** - * @brief create an mpl vector of mixin types - * Every stage in the runtime container contains all the previous ones. - * The resulting mpl vector of this meta function contains all individual - * stages. - * - * Usage: typedef create_rtc_types::type container_types; - */ -template> -struct create_rtc_types -{ - typedef typename boost::mpl::fold< - boost::mpl::range_c - , boost::mpl::vector< > - , boost::mpl::push_back<_1, create_rtc>>> - >::type type; -}; - -};// namespace gNeric -// clang-format on - -#endif diff --git a/Utilities/DataCompression/tpccluster_parameter_model.h b/Utilities/DataCompression/tpccluster_parameter_model.h deleted file mode 100644 index e8455399f17c1..0000000000000 --- a/Utilities/DataCompression/tpccluster_parameter_model.h +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "DataCompression/dc_primitives.h" -#include "DataCompression/HuffmanCodec.h" -#include -#include -#include - -/** - * Parameter model definitions - * - boost mpl vector of alphabets - */ -using tpccluster_parameter = - boost::mpl::vector>, - BitRangeContiguousAlphabet>, - BitRangeContiguousAlphabet>, - BitRangeContiguousAlphabet>, - BitRangeContiguousAlphabet>, - BitRangeContiguousAlphabet>, - BitRangeContiguousAlphabet>>; -/** - * Definition of Huffman probability models for the above defined alphabets - * - * This is a temporary definition, the mpl sequence can be created automatically - * from the list of alphabet types, but did not manage so far (see below) - */ -template -using Model = o2::HuffmanModel>, - o2::HuffmanNode>, true>; - -using tpccluster_parameter_models = - boost::mpl::vector>, - Model>, - Model>, - Model>, - Model>, - Model>, - Model>>; - -/** new approach - using basemodels = foldtype - < tpccluster_parameter, - mpl::lambda>::type - >::type; - - using tpcmodels = foldtype - < basemodels, - mpl::lambda<_, o2::HuffmanNode>>::type - >::type; -*/ - -/** - * this was an attemp to create the vector of Huffman models directly - * from the vector of alphabets - * - * For the moment, the placeholders of mpl fold are not expanded, so there are - * unknown types in the end - */ -/// very first attemp -//using namespace boost::mpl::placeholders; -// -//typedef boost::mpl::fold< -// tpccluster_parameter, -// boost::mpl::vector<>, -// boost::mpl::push_back< -// _1 -// , AliceO2::HuffmanModel< ProbabilityModel< _2 >, AliceO2::HuffmanNode>, true> -// > -// >::type models_t; - -/// trying with additional lambda levels -//typedef boost::mpl::string<'T','e','s','t'>::type TestAlphabetName; -//typedef ContiguousAlphabet TestAlphabet; -// -//typedef typename boost::mpl::lambda< ProbabilityModel< _1 > > apply_alphabet; -//typedef boost::mpl::apply1::type TestAlphabetModel; -//typedef typename boost::mpl::lambda< AliceO2::HuffmanModel< _1, AliceO2::HuffmanNode>, true> > apply_probabilitymodel; -//typedef typename boost::mpl::apply1::type, TestAlphabetModel>::type TestHuffmanModel; -// -//TestAlphabetModel object; -//typedef TestAlphabetModel::value_type vtype; -// -//std::cout << object.getName() << std::endl; - -//typedef boost::mpl::fold< -// tpccluster_parameter, -// boost::mpl::vector<>, -// boost::mpl::push_back< -// _1 -// , boost::mpl::apply1< boost::mpl::protect::type, _2 > -// > -// >::type models_t; diff --git a/Utilities/rANS/include/rANS/internal/containers/HistogramInterface.h b/Utilities/rANS/include/rANS/internal/containers/HistogramInterface.h deleted file mode 100644 index 2c703ede64493..0000000000000 --- a/Utilities/rANS/include/rANS/internal/containers/HistogramInterface.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2019-2023 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 HistogramInterface.h -/// @author Michael Lettrich -/// @brief Operations that will be performed on a histogram - -#ifndef RANS_INTERNAL_CONTAINERS_HISTOGRAMINTERFACE_H_ -#define RANS_INTERNAL_CONTAINERS_HISTOGRAMINTERFACE_H_ - -#include - -#include "rANS/internal/common/utils.h" - -namespace o2::rans::internal -{ - -template -class HistogramInterface -{ - - public: - using source_type = source_T; - using value_type = value_T; - using difference_type = difference_T; - - // operations - template - inline derived_T& addSamples(source_IT begin, source_IT end) - { - static_assert(utils::isCompatibleIter_v); - - if (begin == end) { - return static_cast(*this); - } else { - return static_cast(this)->addSamples(begin, end); - } - }; - - inline derived_T& addSamples(gsl::span samples) - { - return addSamples(samples.data(), samples.data() + samples.size()); - }; - - template - inline derived_T& addFrequencies(freq_IT begin, freq_IT end, difference_type offset) - { - static_assert(utils::isCompatibleIter_v); - - if (begin == end) { - return static_cast(*this); - } else { - return static_cast(this)->addFrequencies(begin, end, offset); - } - }; - - inline derived_T& addFrequencies(gsl::span frequencies, difference_type offset) - { - return addFrequencies(frequencies.data(), frequencies.data() + frequencies.size(), offset); - }; - - derived_T& operator+(derived_T& other) - { - return addFrequencies(other.cbegin(), other.cbegin(), other.getOffset()); - }; - - protected: - HistogramInterface() = default; - - template - HistogramInterface(freq_IT begin, freq_IT end, difference_type offset) - { - static_assert(utils::isIntegralIter_v); - addFrequencies(begin, end, offset); - }; -}; - -} // namespace o2::rans::internal - -#endif /* RANS_INTERNAL_CONTAINERS_HISTOGRAMINTERFACE_H_ */ From c5ead8881e60c064d0c804889da12e1c55edaba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ku=C4=8Dera?= <26327373+vkucera@users.noreply.github.com> Date: Mon, 9 Feb 2026 09:46:24 +0100 Subject: [PATCH 170/234] Algorithm: Delete unused files (#15025) --- Algorithm/include/Algorithm/BitstreamReader.h | 290 ------------------ Algorithm/test/test_BitstreamReader.cxx | 121 -------- 2 files changed, 411 deletions(-) delete mode 100644 Algorithm/include/Algorithm/BitstreamReader.h delete mode 100644 Algorithm/test/test_BitstreamReader.cxx diff --git a/Algorithm/include/Algorithm/BitstreamReader.h b/Algorithm/include/Algorithm/BitstreamReader.h deleted file mode 100644 index 0a112183ab5ef..0000000000000 --- a/Algorithm/include/Algorithm/BitstreamReader.h +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef BITSTREAMREADER_H -#define BITSTREAMREADER_H - -/// @file BitstreamReader.h -/// @author Matthias Richter -/// @since 2019-06-05 -/// @brief Utility class to provide bitstream access to an underlying resource - -#include -#include - -namespace o2 -{ -namespace algorithm -{ - -/// @class BitStreamReader -/// @brief Utility class to provide bitstream access to an underlying resource -/// -/// Allows to access bits of variable length, supports integral types and also -/// bitsets as target type. At the moment, the access is in direction MSB -> LSB. -/// -/// BitstreamReader reader(start, end); -/// while (reader.good() && not reader.eof()) { -/// // get an 8 bit value from the stream, moves the position -/// uint8_t ivalue; -/// reader.get(ivalue); -/// -/// // get a 13 bit bitset without moving the position -/// std::bitset<13> value; -/// reader.peek(value, value.size()); -/// // e.g. use 7 bits of the data -/// value >>= value.size() - 7; -/// // move position by the specific number of bits -/// reader.seek(7); -/// } -template -class BitstreamReader -{ - public: - using self_type = BitstreamReader; - // for the moment we simply use pointers, but with some traits this can be extended to - // containers - using value_type = BufferType; - using iterator = const value_type*; - static constexpr size_t value_size = sizeof(value_type) * 8; - BitstreamReader() = delete; - BitstreamReader(iterator start, iterator end) - : mStart(start), mEnd(end), mCurrent(mStart), mBitPosition(value_size) - { - } - ~BitstreamReader() = default; - - /// Check reader's state - /// @return true if not in error state - bool good() const - { - return mBitPosition > 0; - } - - /// Indicates end of data - /// @return true if end of resource is reached - bool eof() const - { - return mCurrent == mEnd && mBitPosition > 0; - } - - /// Reset the reader, start over at beginning - void reset() - { - mCurrent = mStart; - mBitPosition = value_size; - } - - /// Get the next N bits without moving the read position - /// if bitlength is smaller than the size of data type, result is aligned to LSB - /// TODO: this also works nicely for bitsets, but then the bitlength has to be specified - /// as template parameter, want to do a specific overload, but needs more work to catch - /// all cases. - /// @param v target variable passed by reference - /// @return number of poked bits - template - size_t peek(T& v) - { - static_assert(N <= sizeof(T) * 8); - return peek(v, N); - } - - /// Get the next n bits without moving the read position - /// if bitlength is smaller than the size of data type, result is aligned to LSB - /// @param v target variable passed by reference - /// @param bitlength number of bits to read - /// @return number of poked bits - template - size_t peek(T& v, size_t bitlength) - { - return peek(v, bitlength); - } - - /// Move read position - /// @param bitlength move count in number of bits - void seek(size_t bitlength) - { - while (good() && bitlength > 0 && mCurrent != mEnd) { - if (bitlength >= mBitPosition) { - bitlength -= mBitPosition; - mBitPosition = 0; - } else { - mBitPosition -= bitlength; - bitlength = 0; - } - if (mBitPosition == 0) { - mCurrent++; - mBitPosition = value_size; - } - } - - if (bitlength > 0) { - mBitPosition = 0; - } - } - - /// Get the next n bits and move the read position - template - T get() - { - T result; - peek(result); - seek(N); - return result; - } - - /// Get the next n and move the read position - template - T get(size_t bitlength = sizeof(T) * 8) - { - T result; - peek(result, bitlength); - seek(bitlength); - return result; - } - - /// @class Bits - /// @brief Helper class to get value of specified type which holds the number used bits - /// - /// The class holds both the extracted value access via peek method and the number of used - /// bits. The reader will be incremented when the object is destroyed. - /// The number of bits can be adjusted by using markUsed method - template - class Bits - { - public: - using field_type = FieldType; - static_assert(N <= sizeof(FieldType) * 8); - Bits() - : mParent(nullptr), mData(0), mLength(0) - { - } - Bits(ParentType* parent, FieldType&& data) - : mParent(parent), mData(std::move(data)), mLength(N) - { - } - Bits(Bits&& other) - : mParent(other.mParent), mData(std::move(other.mData)), mLength(other.mLength) - { - other.mParent = nullptr; - other.mLength = 0; - } - - ~Bits() - { - if (mParent) { - mParent->seek(mLength); - } - } - - auto& operator=(Bits&& other) - { - mParent = other.mParent; - mData = std::move(other.mData); - mLength = other.mLength; - other.mParent = nullptr; - other.mLength = 0; - - return *this; - } - - FieldType& operator*() - { - return mData; - } - - void markUsed(size_t length) - { - mLength = length; - } - - private: - ParentType* mParent; - FieldType mData; - size_t mLength; - }; - - /// Read an integral value from the stream - template ::value, int> = 0> - self_type& operator>>(T& target) - { - target = get(); - return *this; - } - - /// Read a bitstream value from the stream - template - self_type& operator>>(std::bitset& target) - { - target = get, N>(); - return *this; - } - - /// Read a Bits object from the stream - template - self_type& operator>>(Bits& target) - { - T bitfield; - peek(bitfield); - target = std::move(Bits(this, std::move(bitfield))); - return *this; - } - - private: - /// The internal peek method - template - size_t peek(T& result, size_t bitlength) - { - if constexpr (RuntimeCheck) { - // the runtime check is disabled if bitlength is derived at compile time - if (bitlength > sizeof(T) * 8) { - throw std::length_error(std::string("requested bit length ") + std::to_string(bitlength) + " does not fit size of result data type " + std::to_string(sizeof(T) * 8)); - } - } - result = 0; - size_t bitsToWrite = bitlength; - auto current = mCurrent; - auto bitsAvailable = mBitPosition; - while (bitsToWrite > 0 && current != mEnd) { - // extract available bits - value_type mask = ~value_type(0) >> (value_size - bitsAvailable); - if (bitsToWrite >= bitsAvailable) { - T value = (*current & mask) << (bitsToWrite - bitsAvailable); - result |= value; - bitsToWrite -= bitsAvailable; - bitsAvailable = 0; - } else { - value_type value = (*current & mask) >> (bitsAvailable - bitsToWrite); - result |= value; - bitsAvailable -= bitsToWrite; - bitsToWrite = 0; - } - if (bitsAvailable == 0) { - current++; - bitsAvailable = value_size; - } - } - - return bitlength - bitsToWrite; - } - - /// start of resource - iterator mStart; - /// end of resource - iterator mEnd; - /// current position in resource - iterator mCurrent; - /// bit position in current element - size_t mBitPosition; -}; -} // namespace algorithm -} // namespace o2 -#endif diff --git a/Algorithm/test/test_BitstreamReader.cxx b/Algorithm/test/test_BitstreamReader.cxx deleted file mode 100644 index 41e3b47f5f276..0000000000000 --- a/Algorithm/test/test_BitstreamReader.cxx +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file test_BitstreamReader.cxx -/// @author Matthias Richter -/// @since 2019-06-05 -/// @brief Test program for BitstreamReader utility - -#define BOOST_TEST_MODULE Algorithm BitstreamReader unit test -#define BOOST_TEST_MAIN -#define BOOST_TEST_DYN_LINK -#include -#include -#include -#include -#include -#include -#include "../include/Algorithm/BitstreamReader.h" - -namespace o2 -{ -namespace algorithm -{ - -BOOST_AUTO_TEST_CASE(test_BitstreamReader_basic) -{ - std::array data = {'d', 'e', 'a', 'd', 'b', 'e', 'e', 'f'}; - std::array expected7bit = {0x32, 0x19, 0x2c, 0x16, 0x23, 0x09, 0x4a, 0x65, 0x33, 0x0}; - auto reference = expected7bit.begin(); - constexpr size_t totalBits = data.size() * sizeof(decltype(data)::value_type) * 8; - size_t bitsRead = 0; - - BitstreamReader reader(data.data(), data.data() + data.size()); - while (bitsRead < totalBits) { - BOOST_REQUIRE(reference != expected7bit.end()); - BOOST_CHECK(reader.eof() == false); - uint8_t value; - reader.peek(value); - // we use 7 bits of the data - value >>= 1; - reader.seek(7); - bitsRead += 7; - // in the last call should there is not enough data - BOOST_CHECK(reader.good() == (bitsRead <= totalBits)); - BOOST_REQUIRE(reference != expected7bit.end()); - //std::cout << "value " << (int)value << " expected " << (int)*reference << std::endl; - BOOST_CHECK(value == *reference); - ++reference; - } -} - -BOOST_AUTO_TEST_CASE(test_BitstreamReader_operator) -{ - std::array data = {'d', 'e', 'a', 'd', 'b', 'e', 'e', 'f'}; - std::array expected7bit = {0x32, 0x19, 0x2c, 0x16, 0x23, 0x09, 0x4a, 0x65, 0x33, 0x0}; - auto reference = expected7bit.begin(); - constexpr size_t totalBits = data.size() * sizeof(decltype(data)::value_type) * 8; - size_t bitsRead = 0; - - BitstreamReader reader(data.data(), data.data() + data.size()); - while (bitsRead < totalBits) { - BOOST_REQUIRE(reference != expected7bit.end()); - BOOST_CHECK(reader.eof() == false); - { - decltype(reader)::Bits value; - reader >> value; - // we use 7 bits of the data - *value >>= 1; - value.markUsed(7); - //std::cout << "value " << (int)*value << " expected " << (int)*reference << std::endl; - BOOST_CHECK(*value == *reference); - } - bitsRead += 7; - // in the last call should there is not enough data - BOOST_CHECK(reader.good() == (bitsRead <= totalBits)); - BOOST_REQUIRE(reference != expected7bit.end()); - ++reference; - } -} - -BOOST_AUTO_TEST_CASE(test_BitstreamReader_bitset) -{ - std::array data = {'d', 'e', 'a', 'd', 'b', 'e', 'e', 'f'}; - std::array expected7bit = {0x32, 0x19, 0x2c, 0x16, 0x23, 0x09, 0x4a, 0x65, 0x33, 0x0}; - auto reference = expected7bit.begin(); - constexpr size_t totalBits = data.size() * sizeof(decltype(data)::value_type) * 8; - size_t bitsRead = 0; - - BitstreamReader reader(data.data(), data.data() + data.size()); - while (bitsRead < totalBits) { - BOOST_REQUIRE(reference != expected7bit.end()); - BOOST_CHECK(reader.eof() == false); - std::bitset<13> value; - reader.peek(value, value.size()); - // we use 7 bits of the data - value >>= value.size() - 7; - reader.seek(7); - bitsRead += 7; - // in the last call should there is not enough data - BOOST_CHECK(reader.good() == (bitsRead <= totalBits)); - BOOST_REQUIRE(reference != expected7bit.end()); - BOOST_CHECK_MESSAGE(value.to_ulong() == *reference, std::string("mismatch: value ") << value.to_ulong() << ", expected " << (int)*reference); - ++reference; - } - - reader.reset(); - std::bitset<16> aBitset; - reader >> aBitset; - BOOST_CHECK_MESSAGE(aBitset.to_ulong() == 0x6465, std::string("mismatch: value 0x") << std::hex << aBitset.to_ulong() << ", expected 0x6465"); -} - -} // namespace algorithm -} // namespace o2 From 7830e9c54db7ef479c0c8710c4b934c27312e2d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ku=C4=8Dera?= <26327373+vkucera@users.noreply.github.com> Date: Mon, 9 Feb 2026 10:10:31 +0100 Subject: [PATCH 171/234] DataFormats: Delete unused files (#15029) --- .../include/Headers/SubframeMetadata.h | 68 ----- .../HLT/include/AliceHLT/TPCRawCluster.h | 232 ------------------ 2 files changed, 300 deletions(-) delete mode 100644 DataFormats/Headers/include/Headers/SubframeMetadata.h delete mode 100644 DataFormats/Legacy/HLT/include/AliceHLT/TPCRawCluster.h diff --git a/DataFormats/Headers/include/Headers/SubframeMetadata.h b/DataFormats/Headers/include/Headers/SubframeMetadata.h deleted file mode 100644 index 255fa0ceb8db6..0000000000000 --- a/DataFormats/Headers/include/Headers/SubframeMetadata.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef SUBFRAMEMETADATA_H -#define SUBFRAMEMETADATA_H - -#include - -namespace o2 -{ -namespace data_flow -{ - -struct SubframeMetadata { - // TODO: replace with timestamp struct - // IDEA: not timeframeID because can be calculcated with helper function - // QUESTION: isn't the duration set to ~22ms? - uint64_t startTime = ~(uint64_t)0; - uint64_t duration = ~(uint64_t)0; - - //further meta data to be added - - // putting data specific to FLP origin - int flpIndex; -}; - -// Helper function to derive the timeframe id from the actual timestamp. -// Timestamp is in nanoseconds. Each Timeframe is ~22ms i.e. 2^17 nanoseconds, -// so we can get a unique id by dividing by the timeframe period and masking -// the lower 16 bits. Overlaps will only happen every ~ 22 minutes. -constexpr uint16_t - timeframeIdFromTimestamp(uint64_t timestamp, uint64_t timeFrameDuration) -{ - return (timestamp / timeFrameDuration) & 0xffff; -} - -// A Mockup class to describe some TPC-like payload -struct TPCTestCluster { - float x = 0.f; - float y = 0.f; - float z = 1.5f; - float q = 0.; - uint64_t timeStamp; // the time this thing was digitized/recorded -}; - -struct TPCTestPayload { - std::vector clusters; -}; - -// a mockup class to describe some "ITS" payload -struct ITSRawData { - float x = -1.; - float y = 1.; - uint64_t timeStamp; -}; - -} // namespace data_flow -} // namespace o2 - -#endif diff --git a/DataFormats/Legacy/HLT/include/AliceHLT/TPCRawCluster.h b/DataFormats/Legacy/HLT/include/AliceHLT/TPCRawCluster.h deleted file mode 100644 index 59be2a86c3c2b..0000000000000 --- a/DataFormats/Legacy/HLT/include/AliceHLT/TPCRawCluster.h +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -//-*- Mode: C++ -*- - -#ifndef TPCRAWCLUSTER_H -#define TPCRAWCLUSTER_H -//**************************************************************************** -//* This file is free software: you can redistribute it and/or modify * -//* it under the terms of the GNU General Public License as published by * -//* the Free Software Foundation, either version 3 of the License, or * -//* (at your option) any later version. * -//* * -//* Primary Authors: Matthias Richter * -//* * -//* The authors make no claims about the suitability of this software for * -//* any purpose. It is provided "as is" without express or implied warranty. * -//**************************************************************************** - -// @file TPCRawCluster.h -// @author Matthias Richter -// @since 2015-09-27 -// @brief ALICE HLT TPC raw cluster structure and tools - -#include -#include // ifstream -#include // memcpy - -namespace o2 -{ -namespace AliceHLT -{ - -/** - * @struct RawCluster - * This is a redefinition from AliRoot/HLT/TPCLib/AliHLTTPCRawCluster.h for the - * sake of reading HLT TPC raw cluster files into O2. - * - * TODO: there is no dependence on AliRoot, however, a test needs to be added - * to check consistency if AliRoot is available in the build. - */ -struct RawCluster { - - int16_t GetPadRow() const { return fPadRow; } - float GetPad() const { return fPad; } - float GetTime() const { return fTime; } - float GetSigmaPad2() const { return fSigmaPad2; } - float GetSigmaTime2() const { return fSigmaTime2; } - int32_t GetCharge() const { return fCharge; } - int32_t GetQMax() const { return fQMax; } - bool GetFlagSplitPad() const { return (fFlags & (1 << 0)); } - bool GetFlagSplitTime() const { return (fFlags & (1 << 1)); } - bool GetFlagSplitAny() const { return (fFlags & 3); } - uint16_t GetFlags() const { return (fFlags); } - - int16_t fPadRow; - uint16_t fFlags; //Flags: (1 << 0): Split in pad direction - // (1 << 1): Split in time direction - //During cluster merging, flags are or'd - float fPad; - float fTime; - float fSigmaPad2; - float fSigmaTime2; - uint16_t fCharge; - uint16_t fQMax; -}; - -/** - * @struct RawClusterData - * Header data struct for a raw cluster block - */ -struct RawClusterData { - uint32_t fVersion; // version number - uint32_t fCount; // number of clusters - RawCluster fClusters[0]; // array of clusters -}; - -std::ostream& operator<<(std::ostream& stream, const RawCluster& cluster) -{ - stream << "TPCRawCluster:" - << " " << cluster.GetPadRow() - << " " << cluster.GetPad() - << " " << cluster.GetTime() - << " " << cluster.GetSigmaPad2() - << " " << cluster.GetSigmaTime2() - << " " << cluster.GetCharge() - << " " << cluster.GetQMax(); - return stream; -} - -/** - * @class RawClusterArray Wrapper to binary data block of HLT TPC raw clusters - * Container class which provides access to the content of a binary block of - * HLT TPC raw clusters. - */ -class RawClusterArray -{ - public: - RawClusterArray() : mBuffer(nullptr), mBufferSize(0), mNClusters(0), mClusters(NULL), mClustersEnd(NULL) {} - RawClusterArray(const char* filename) : mBuffer(nullptr), mBufferSize(0), mNClusters(0), mClusters(NULL), mClustersEnd(NULL) - { - init(filename); - } - RawClusterArray(unsigned char* buffer, int size) : mBuffer(nullptr), mBufferSize(0), mNClusters(0), mClusters(NULL), mClustersEnd(NULL) - { - init(buffer, size); - } - ~RawClusterArray() {} - - typedef uint8_t Buffer_t; - - int init(const char* filename) - { - std::ifstream input(filename, std::ifstream::binary); - clear(0); - if (input) { - // get length of file: - input.seekg(0, input.end); - int length = input.tellg(); - input.seekg(0, input.beg); - - // allocate memory: - mBuffer = new Buffer_t[length]; - mBufferSize = length; - - // read data as a block: - input.read(reinterpret_cast(mBuffer), length); - if (!input.good()) { - clear(-1); - std::cerr << "failed to read " << length << " byte(s) from file " << filename << std::endl; - } - - input.close(); - return init(); - } - std::cerr << "failed to open file " << filename << std::endl; - return -1; - } - - int init(unsigned char* buffer, int size) - { - if (!buffer || size <= 0) - return -1; - clear(0); - mBuffer = new Buffer_t[size]; - mBufferSize = size; - memcpy(mBuffer, buffer, size); - return init(); - } - - int GetNClusters() const { return mNClusters; } - - RawCluster* begin() { return mClusters; } - - RawCluster* end() { return mClustersEnd; } - - RawCluster& operator[](int i) - { - if (i + 1 > mNClusters) { - // runtime exeption? - static RawCluster dummy; - return dummy; - } - return *(mClusters + i); - } - - void print() { print(std::cout); } - - template - StreamT& print(StreamT& stream) - { - std::cout << "RawClusterArray: " << mNClusters << " cluster(s)" << std::endl; - for (RawCluster* cluster = mClusters; cluster != mClustersEnd; cluster++) { - std::cout << " " << *cluster << std::endl; - } - return stream; - } - - private: - int init() - { - if (mBuffer == nullptr || mBufferSize == 0) - return 0; - if (mBufferSize < sizeof(RawClusterData)) - return -1; - RawClusterData& clusterData = *reinterpret_cast(mBuffer); - - if (clusterData.fCount * sizeof(RawCluster) + sizeof(RawClusterData) > mBufferSize) { - std::cerr << "Format error, " << clusterData.fCount << " cluster(s) " - << "would require " - << (clusterData.fCount * sizeof(RawCluster) + sizeof(RawClusterData)) - << " byte(s), but only " << mBufferSize << " available" << std::endl; - return clear(-1); - } - - mNClusters = clusterData.fCount; - mClusters = clusterData.fClusters; - mClustersEnd = mClusters + mNClusters; - - return mNClusters; - } - - int clear(int returnValue) - { - mNClusters = 0; - mClusters = NULL; - mClustersEnd = NULL; - delete[] mBuffer; - mBuffer = nullptr; - mBufferSize = 0; - - return returnValue; - } - - Buffer_t* mBuffer; - int mBufferSize; - int mNClusters; - RawCluster* mClusters; - RawCluster* mClustersEnd; -}; - -}; // namespace AliceHLT -}; // namespace o2 -#endif From 99d03b950769c309102f0a7d2cb7805e329f15ee Mon Sep 17 00:00:00 2001 From: Ernst Hellbar Date: Fri, 9 Jan 2026 15:15:52 +0000 Subject: [PATCH 172/234] Event Display: remove return statements from handled filesystem exceptions --- EventVisualisation/Base/src/DirectoryLoader.cxx | 3 --- 1 file changed, 3 deletions(-) diff --git a/EventVisualisation/Base/src/DirectoryLoader.cxx b/EventVisualisation/Base/src/DirectoryLoader.cxx index f2f5a421c0ef9..50b3de61295a3 100644 --- a/EventVisualisation/Base/src/DirectoryLoader.cxx +++ b/EventVisualisation/Base/src/DirectoryLoader.cxx @@ -37,7 +37,6 @@ deque DirectoryLoader::load(const std::string& path, const std::string& } } catch (std::filesystem::filesystem_error const& ex) { LOGF(error, "filesystem problem during DirectoryLoader::load: %s", ex.what()); - return result; } // comparison with safety if marker not in the filename (-1+1 gives 0) std::sort(result.begin(), result.end(), @@ -62,7 +61,6 @@ bool DirectoryLoader::canCreateNextFile(const std::vector& paths, c } } catch (std::filesystem::filesystem_error const& ex) { LOGF(error, "filesystem problem during DirectoryLoader::canCreateNextFile: %s", ex.what()); - return false; } } @@ -103,7 +101,6 @@ deque DirectoryLoader::load(const std::vector& paths, const } } catch (std::filesystem::filesystem_error const& ex) { LOGF(error, "filesystem problem during DirectoryLoader::load: %s", ex.what()); - return result; } // comparison with safety if marker not in the filename (-1+1 gives 0) std::sort(result.begin(), result.end(), From 28dcfc4269c76c97a71081f8f4835d0e9ce7e196 Mon Sep 17 00:00:00 2001 From: Ernst Hellbar Date: Thu, 15 Jan 2026 15:17:28 +0100 Subject: [PATCH 173/234] Event Display: add OnlineMode and safety checks --- .../Base/src/DirectoryLoader.cxx | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/EventVisualisation/Base/src/DirectoryLoader.cxx b/EventVisualisation/Base/src/DirectoryLoader.cxx index 50b3de61295a3..e106eaf7ebb47 100644 --- a/EventVisualisation/Base/src/DirectoryLoader.cxx +++ b/EventVisualisation/Base/src/DirectoryLoader.cxx @@ -14,6 +14,8 @@ /// \author julian.myrcha@cern.ch #include "EventVisualisationBase/DirectoryLoader.h" +#include "Framework/DefaultsHelpers.h" +#include "Framework/DataTakingContext.h" #include #include #include @@ -65,10 +67,13 @@ bool DirectoryLoader::canCreateNextFile(const std::vector& paths, c } // comparison with safety if marker not in the filename (-1+1 gives 0) - std::ranges::sort(result.begin(), result.end(), - [marker](const std::string& a, const std::string& b) { - return a.substr(a.find_first_of(marker) + 1) > b.substr(b.find_first_of(marker) + 1); - }); + if (result.size() > 1) { + std::ranges::sort(result.begin(), result.end(), + [marker](const std::string& a, const std::string& b) { + return a.substr(a.find_first_of(marker) + 1) > b.substr(b.find_first_of(marker) + 1); + }); + } + unsigned long accumulatedSize = 0L; const std::regex delimiter{"_"}; for (auto const& file : result) { @@ -113,11 +118,15 @@ deque DirectoryLoader::load(const std::vector& paths, const std::vector DirectoryLoader::allFolders(const std::string& location) { - auto const pos = location.find_last_of('_'); std::vector folders; - folders.push_back(location.substr(0, pos) + "_PHYSICS"); - folders.push_back(location.substr(0, pos) + "_COSMICS"); - folders.push_back(location.substr(0, pos) + "_SYNTHETIC"); + if (o2::framework::DefaultsHelpers::deploymentMode() == o2::framework::DeploymentMode::OnlineDDS) { + auto const pos = location.find_last_of('_'); + folders.push_back(location.substr(0, pos) + "_PHYSICS"); + folders.push_back(location.substr(0, pos) + "_COSMICS"); + folders.push_back(location.substr(0, pos) + "_SYNTHETIC"); + } else { + folders.push_back(location); + } return folders; } From 1452f31b25e3ec1633e02e1a8f6151210b6bb70c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ku=C4=8Dera?= <26327373+vkucera@users.noreply.github.com> Date: Mon, 9 Feb 2026 23:46:22 +0100 Subject: [PATCH 174/234] Framework: Delete unused files (#15038) --- .../Framework/DataProcessingStateManager.h | 35 ---- Framework/Foundation/src/Traits.cxx | 10 -- Framework/TestWorkflows/src/dummy.cxx | 10 -- Framework/TestWorkflows/src/o2_sim_its_ALP3.h | 25 --- Framework/TestWorkflows/src/o2_sim_tpc.cxx | 157 ------------------ Framework/TestWorkflows/src/o2_sim_tpc.h | 25 --- .../src/test_o2ITSCluserizer.cxx | 32 ---- .../src/test_o2TPCSimulation.cxx | 31 ---- Framework/Utils/test/DPLBroadcasterMerger.cxx | 147 ---------------- Framework/Utils/test/DPLBroadcasterMerger.h | 28 ---- Framework/Utils/test/DPLOutputTest.h | 28 ---- .../Utils/test/test_DPLBroadcasterMerger.cxx | 31 ---- Framework/Utils/test/test_DPLOutputTest.cxx | 31 ---- 13 files changed, 590 deletions(-) delete mode 100644 Framework/Core/include/Framework/DataProcessingStateManager.h delete mode 100644 Framework/Foundation/src/Traits.cxx delete mode 100644 Framework/TestWorkflows/src/dummy.cxx delete mode 100644 Framework/TestWorkflows/src/o2_sim_its_ALP3.h delete mode 100644 Framework/TestWorkflows/src/o2_sim_tpc.cxx delete mode 100644 Framework/TestWorkflows/src/o2_sim_tpc.h delete mode 100644 Framework/TestWorkflows/src/test_o2ITSCluserizer.cxx delete mode 100644 Framework/TestWorkflows/src/test_o2TPCSimulation.cxx delete mode 100644 Framework/Utils/test/DPLBroadcasterMerger.cxx delete mode 100644 Framework/Utils/test/DPLBroadcasterMerger.h delete mode 100644 Framework/Utils/test/DPLOutputTest.h delete mode 100644 Framework/Utils/test/test_DPLBroadcasterMerger.cxx delete mode 100644 Framework/Utils/test/test_DPLOutputTest.cxx diff --git a/Framework/Core/include/Framework/DataProcessingStateManager.h b/Framework/Core/include/Framework/DataProcessingStateManager.h deleted file mode 100644 index eaa1c8e4e5501..0000000000000 --- a/Framework/Core/include/Framework/DataProcessingStateManager.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_DATAPROCESSINGSTATEMANAGER_H_ -#define O2_DATAPROCESSINGSTATEMANAGER_H_ - -#include -#include -#include - -struct DataProcessingStateManager { - struct StateIndex { - short id = -1; - short index = -1; - }; - struct StateInfo { - std::string name; - int64_t lastUpdate = 0; - int index = -1; - }; - - static constexpr int MAX_STATES = 1024; - std::vector> states = {}; - std::vector infos = {}; -}; - -#endif diff --git a/Framework/Foundation/src/Traits.cxx b/Framework/Foundation/src/Traits.cxx deleted file mode 100644 index faff430964e73..0000000000000 --- a/Framework/Foundation/src/Traits.cxx +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. diff --git a/Framework/TestWorkflows/src/dummy.cxx b/Framework/TestWorkflows/src/dummy.cxx deleted file mode 100644 index faff430964e73..0000000000000 --- a/Framework/TestWorkflows/src/dummy.cxx +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. diff --git a/Framework/TestWorkflows/src/o2_sim_its_ALP3.h b/Framework/TestWorkflows/src/o2_sim_its_ALP3.h deleted file mode 100644 index f9c465fcf5717..0000000000000 --- a/Framework/TestWorkflows/src/o2_sim_its_ALP3.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef WORKFLOWS_O2_SIM_ITS_ALP3 -#define WORKFLOWS_O2_SIM_ITS_ALP3 - -#include "Framework/DataProcessorSpec.h" - -namespace o2 -{ -namespace workflows -{ -o2::framework::DataProcessorSpec sim_its_ALP3(); -} -} // namespace o2 - -#endif // WORKFLOWS_O2_SIM_ITS_ALP3 diff --git a/Framework/TestWorkflows/src/o2_sim_tpc.cxx b/Framework/TestWorkflows/src/o2_sim_tpc.cxx deleted file mode 100644 index 4587c0fcb831f..0000000000000 --- a/Framework/TestWorkflows/src/o2_sim_tpc.cxx +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/DataRefUtils.h" -#include "Framework/WorkflowSpec.h" -#include -#include "Framework/RootFileService.h" -#include "Framework/AlgorithmSpec.h" -#include "Framework/ConfigParamRegistry.h" - -#include "Framework/Logger.h" - -#include "FairRunSim.h" -#include -#include "FairRuntimeDb.h" -#include "FairPrimaryGenerator.h" -#include "FairBoxGenerator.h" -#include "FairParRootFileIo.h" - -#include "DetectorsPassive/Cave.h" -#include "Field/MagneticField.h" - -#include "DetectorsPassive/Cave.h" -#include "Generators/GeneratorFromFile.h" -#include "TPCSimulation/Detector.h" -#include "Framework/OutputSpec.h" -#include - -using namespace o2::framework; - -#define BOX_GENERATOR 1 - -namespace o2 -{ -namespace workflows -{ - -DataProcessorSpec sim_tpc() -{ - return { - "sim_tpc", - Inputs{}, - Outputs{OutputSpec{"TPC", "GEN"}}, - AlgorithmSpec{ - [](InitContext& setup) { - int nEvents = setup.options().get("nEvents"); - auto mcEngine = setup.options().get("mcEngine"); - - // FIXME: this should probably be part of some generic - // FairRunInitSpec - TString dir = getenv("VMCWORKDIR"); - TString geom_dir = dir + "/Detectors/Geometry/"; - gSystem->Setenv("GEOMPATH", geom_dir.Data()); - - TString tut_configdir = dir + "/Detectors/gconfig"; - gSystem->Setenv("CONFIG_DIR", tut_configdir.Data()); - - // Requiring a file is something which requires IO, and it's therefore - // delegated to the framework - auto& rfm = setup.services().get(); - // FIXME: We should propably have a service for FairRunSim, rather than - // for the root files themselves... - // Output file name - auto outFile = rfm.format("AliceO2_%s.tpc.mc_%i_event.root", mcEngine.c_str(), nEvents); - - // Parameter file name - auto parFile = rfm.format("AliceO2_%s.tpc.mc_%i_event.root", mcEngine.c_str(), nEvents); - - // Create simulation run - FairRunSim* run = new FairRunSim(); - - run->SetName(mcEngine.c_str()); - run->SetSink(new FairRootFileSink(outFile.c_str())); // Output file - FairRuntimeDb* rtdb = run->GetRuntimeDb(); - - // Create media - run->SetMaterials("media.geo"); // Materials - - // Create geometry - o2::passive::Cave* cave = new o2::passive::Cave("CAVE"); - cave->SetGeometryFileName("cave.geo"); - run->AddModule(cave); - - o2::field::MagneticField* magField = new o2::field::MagneticField("Maps", "Maps", -1., -1., o2::field::MagFieldParam::k5kG); - run->SetField(magField); - - // ===| Add TPC |============================================================ - o2::tpc::Detector* tpc = new o2::tpc::Detector(kTRUE); - tpc->SetGeoFileName("TPCGeometry.root"); - run->AddModule(tpc); - - // Create PrimaryGenerator - FairPrimaryGenerator* primGen = new FairPrimaryGenerator(); -#ifdef BOX_GENERATOR - FairBoxGenerator* boxGen = new FairBoxGenerator(211, 10); /*protons*/ - - //boxGen->SetThetaRange(0.0, 90.0); - boxGen->SetEtaRange(-0.9, 0.9); - boxGen->SetPRange(0.1, 5); - boxGen->SetPhiRange(0., 360.); - boxGen->SetDebug(kTRUE); - - primGen->AddGenerator(boxGen); -#else - // reading the events from a kinematics file (produced by AliRoot) - auto extGen = new o2::eventgen::GeneratorFromFile(params.get("extKinFile")); - extGen->SetStartEvent(params.get("startEvent")); - primGen->AddGenerator(extGen); -#endif - - run->SetGenerator(primGen); - - // store track trajectories - // run->SetStoreTraj(kTRUE); - - // Initialize simulation run - run->Init(); - - // Runtime database - Bool_t kParameterMerged = kTRUE; - FairParRootFileIo* parOut = new FairParRootFileIo(kParameterMerged); - parOut->open(parFile.c_str()); - rtdb->setOutput(parOut); - rtdb->saveOutput(); - rtdb->print(); - run->Run(nEvents); - - static bool once = true; - - // This is the actual inner loop for the device - return [run, nEvents](ProcessingContext& ctx) { - if (!once) { - run->Run(nEvents); - once = true; - } else { - std::this_thread::sleep_for(std::chrono::seconds(1)); - } - // FIXME: After we run we should readback events - // and push them as messages, for the next stage of - // processing. - }; - }}, - Options{ - {"mcEngine", VariantType::String, "TGeant3", {"Engine to use"}}, - {"nEvents", VariantType::Int, 10, {"Events to process"}}, - {"extKinFile", VariantType::String, "Kinematics.root", {"name of kinematics file for event generator from file (when applicable)"}}, - {"startEvent", VariantType::Int, 2, {"Events to skip"}}}}; -}; -} // namespace workflows -} // namespace o2 diff --git a/Framework/TestWorkflows/src/o2_sim_tpc.h b/Framework/TestWorkflows/src/o2_sim_tpc.h deleted file mode 100644 index e567fe89e0b38..0000000000000 --- a/Framework/TestWorkflows/src/o2_sim_tpc.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef WORKFLOWS_O2_SIM_TPC -#define WORKFLOWS_O2_SIM_TPC - -#include "Framework/DataProcessorSpec.h" - -namespace o2 -{ -namespace workflows -{ -o2::framework::DataProcessorSpec sim_tpc(); -} -} // namespace o2 - -#endif // WORKFLOWS_O2_SIM_TPC diff --git a/Framework/TestWorkflows/src/test_o2ITSCluserizer.cxx b/Framework/TestWorkflows/src/test_o2ITSCluserizer.cxx deleted file mode 100644 index d6d3cb1242f7c..0000000000000 --- a/Framework/TestWorkflows/src/test_o2ITSCluserizer.cxx +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/DataRefUtils.h" -#include "Framework/ServiceRegistry.h" -#include "Framework/runDataProcessing.h" -#include -// FIXME: this should not be needed as the framework should be able to -// decode TClonesArray by itself. -#include "Framework/TMessageSerializer.h" -#include "o2_sim_its_ALP3.h" -#include "Framework/Logger.h" -#include -#include - -using namespace o2::framework; -using namespace o2::workflows; - -// This is how you can define your processing in a declarative way -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return WorkflowSpec{ - sim_its_ALP3(), - }; -} diff --git a/Framework/TestWorkflows/src/test_o2TPCSimulation.cxx b/Framework/TestWorkflows/src/test_o2TPCSimulation.cxx deleted file mode 100644 index 403ad8bc7127b..0000000000000 --- a/Framework/TestWorkflows/src/test_o2TPCSimulation.cxx +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -#include "Framework/DataRefUtils.h" -#include "Framework/ServiceRegistry.h" -#include "Framework/runDataProcessing.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/DataRef.h" -// FIXME: this should not be needed as the framework should be able to -// decode TClonesArray by itself. -#include "Framework/TMessageSerializer.h" -#include "o2_sim_tpc.h" -#include "Framework/Logger.h" - -using namespace o2::framework; -using namespace o2::workflows; - -// This is how you can define your processing in a declarative way -WorkflowSpec defineDataProcessing(ConfigContext const& specs) -{ - return WorkflowSpec{ - sim_tpc(), - }; -} diff --git a/Framework/Utils/test/DPLBroadcasterMerger.cxx b/Framework/Utils/test/DPLBroadcasterMerger.cxx deleted file mode 100644 index bf793275d2f3f..0000000000000 --- a/Framework/Utils/test/DPLBroadcasterMerger.cxx +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \author Gabriele Gaetano Fronzé, gfronze@cern.ch - -#include -#include "DPLBroadcasterMerger.h" -#include "DPLUtils/Utils.h" -#include "Framework/DataProcessorSpec.h" -#include "Framework/ControlService.h" -#include "Framework/DataRefUtils.h" -#include "random" -#include "Framework/Logger.h" -#include - -namespace o2f = o2::framework; - -namespace o2::workflows -{ - -o2f::Inputs noInputs{}; -o2f::Outputs noOutputs{}; - -o2f::DataProcessorSpec defineGenerator(o2f::OutputSpec usrOutput) -{ - return {"Generator", // Device name - noInputs, // No inputs for a generator - o2f::Outputs{usrOutput}, // One simple output - - o2f::AlgorithmSpec{[usrOutput](o2f::InitContext&) { - int msgCounter = 0; - auto msgCounter_shptr = std::make_shared(msgCounter); - auto usrOutput_shptr = std::make_shared(getOutput(usrOutput)); - - LOG(info) << ">>>>>>>>>>>>>> Generator initialised"; - - // Processing context in captured from return on InitCallback - return [usrOutput_shptr, msgCounter_shptr](o2f::ProcessingContext& ctx) { - int msgIndex = (*msgCounter_shptr)++; - if (msgIndex > 10) { - ctx.services().get().endOfStream(); - } - LOG(info) << ">>> MSG:" << msgIndex; - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - - LOG(info) << ">>> Preparing MSG:" << msgIndex; - - auto& outputMsg = - ctx.outputs().newChunk(*usrOutput_shptr, (msgIndex + 1) * sizeof(uint32_t) / sizeof(char)); - - LOG(info) << ">>> Preparing1 MSG:" << msgIndex; - - auto payload = reinterpret_cast(outputMsg.data()); - - payload[0] = msgIndex; - - LOG(info) << ">>> Preparing2 MSG:" << msgIndex; - - for (int k = 0; k < msgIndex; ++k) { - payload[k + 1] = (uint32_t)32; - LOG(info) << ">>>>\t" << payload[k + 1]; - } - - return; - }; - }}}; -} - -o2f::DataProcessorSpec definePipeline(std::string devName, o2f::InputSpec usrInput, o2f::OutputSpec usrOutput) -{ - return {devName, // Device name - o2f::Inputs{usrInput}, // No inputs, for the moment - o2f::Outputs{usrOutput}, o2f::AlgorithmSpec{[usrOutput](o2f::InitContext&) { - auto output_sharedptr = std::make_shared(getOutput(usrOutput)); - - // Processing context in captured from return on InitCallback - return [output_sharedptr](o2f::ProcessingContext& ctx) { - auto inputMsg = ctx.inputs().getByPos(0); - auto msgSize = o2::framework::DataRefUtils::getPayloadSize(inputMsg); - - auto& fwdMsg = ctx.outputs().newChunk((*output_sharedptr), msgSize); - std::memcpy(fwdMsg.data(), inputMsg.payload, msgSize); - }; - }}}; -} - -o2f::DataProcessorSpec defineSink(o2f::InputSpec usrInput) -{ - return {"Sink", // Device name - o2f::Inputs{usrInput}, // No inputs, for the moment - noOutputs, - - o2f::AlgorithmSpec{[](o2f::InitContext&) { - // Processing context in captured from return on InitCallback - return [](o2f::ProcessingContext& ctx) { - LOG(info) << "Received message "; - - auto inputMsg = ctx.inputs().getByPos(0); - auto payload = reinterpret_cast(inputMsg.payload); - - LOG(info) << "Received message containing" << payload[0] << "elements"; - - for (int j = 0; j < payload[0]; ++j) { - LOG(info) << payload[j + 1] << "\t"; - } - LOG(info); - }; - }}}; -} - -o2::framework::WorkflowSpec DPLBroadcasterMergerWorkflow() -{ - auto lspec = o2f::WorkflowSpec(); - - // A generator of data - lspec.emplace_back(defineGenerator(o2f::OutputSpec{"TST", "ToBC", 0, o2f::Lifetime::Timeframe})); - - // A two-way broadcaster - lspec.emplace_back(defineBroadcaster("Broadcaster", - o2f::InputSpec{"input", "TST", "ToBC", 0, o2f::Lifetime::Timeframe}, - o2f::Outputs{{"TST", "BCAST0", 0, o2f::Lifetime::Timeframe}, - {"TST", "BCAST1", 0, o2f::Lifetime::Timeframe}})); - - // Two pipeline devices - lspec.emplace_back(definePipeline("pip0", o2f::InputSpec{"bc", "TST", "BCAST0", 0, o2f::Lifetime::Timeframe}, - o2f::OutputSpec{"TST", "PIP0", 0, o2f::Lifetime::Timeframe})); - lspec.emplace_back(definePipeline("pip1", o2f::InputSpec{"bc", "TST", "BCAST1", 0, o2f::Lifetime::Timeframe}, - o2f::OutputSpec{"TST", "PIP1", 0, o2f::Lifetime::Timeframe})); - - // A gatherer - lspec.emplace_back(defineMerger("Merger", o2f::Inputs{{"input1", "TST", "PIP0", 0, o2f::Lifetime::Timeframe}, {"input2", "TST", "PIP1", 0, o2f::Lifetime::Timeframe}}, - o2f::OutputSpec{"TST", "ToSink", 0, o2f::Lifetime::Timeframe})); - - // A sink which dumps messages - lspec.emplace_back(defineSink(o2f::InputSpec{"input", "TST", "ToSink", 0, o2f::Lifetime::Timeframe})); - return std::move(lspec); -} - -} // namespace o2::workflows diff --git a/Framework/Utils/test/DPLBroadcasterMerger.h b/Framework/Utils/test/DPLBroadcasterMerger.h deleted file mode 100644 index 4607d72a702b7..0000000000000 --- a/Framework/Utils/test/DPLBroadcasterMerger.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \author Gabriele Gaetano Fronzé, gfronze@cern.ch - -#ifndef DPLBROADCASTERMERGER_H -#define DPLBROADCASTERMERGER_H - -#include "Framework/WorkflowSpec.h" -#include "Framework/DataProcessorSpec.h" - -namespace o2 -{ -namespace workflows -{ -o2::framework::WorkflowSpec DPLBroadcasterMergerWorkflow(); -} -} // namespace o2 - -#endif // DPLBROADCASTERMERGER_H diff --git a/Framework/Utils/test/DPLOutputTest.h b/Framework/Utils/test/DPLOutputTest.h deleted file mode 100644 index ce776ffff1113..0000000000000 --- a/Framework/Utils/test/DPLOutputTest.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \author Gabriele Gaetano Fronzé, gfronze@cern.ch - -#ifndef DPLOUTPUTTEST_H -#define DPLOUTPUTTEST_H - -#include "Framework/WorkflowSpec.h" -#include "Framework/DataProcessorSpec.h" - -namespace o2 -{ -namespace workflows -{ -o2::framework::WorkflowSpec DPLOutputTest(); -} -} // namespace o2 - -#endif // DPLOUTPUTTEST_H diff --git a/Framework/Utils/test/test_DPLBroadcasterMerger.cxx b/Framework/Utils/test/test_DPLBroadcasterMerger.cxx deleted file mode 100644 index 6ff554e75f462..0000000000000 --- a/Framework/Utils/test/test_DPLBroadcasterMerger.cxx +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \author Gabriele Gaetano Fronzé, gfronze@cern.ch - -#include "Framework/DataRefUtils.h" -#include "Framework/ServiceRegistry.h" -#include "Framework/runDataProcessing.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/DataRef.h" -// FIXME: this should not be needed as the framework should be able to -// decode TClonesArray by itself. -#include "Framework/TMessageSerializer.h" -#include "DPLBroadcasterMerger.h" -#include "Framework/Logger.h" - -using namespace o2::framework; - -// This is how you can define your processing in a declarative way -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return o2::workflows::DPLBroadcasterMergerWorkflow(); -} diff --git a/Framework/Utils/test/test_DPLOutputTest.cxx b/Framework/Utils/test/test_DPLOutputTest.cxx deleted file mode 100644 index e49bea3074dd1..0000000000000 --- a/Framework/Utils/test/test_DPLOutputTest.cxx +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \author Gabriele Gaetano Fronzé, gfronze@cern.ch - -#include "Framework/DataRefUtils.h" -#include "Framework/ServiceRegistry.h" -#include "Framework/runDataProcessing.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/DataRef.h" -// FIXME: this should not be needed as the framework should be able to -// decode TClonesArray by itself. -#include "Framework/TMessageSerializer.h" -#include "DPLOutputTest.h" -#include "Framework/Logger.h" - -using namespace o2::framework; - -// This is how you can define your processing in a declarative way -WorkflowSpec defineDataProcessing(ConfigContext const&) -{ - return o2::workflows::DPLOutputTest(); -} From 1fd232899d168aab1eaa344aab5562589f7195a2 Mon Sep 17 00:00:00 2001 From: Stefano Cannito <143754257+scannito@users.noreply.github.com> Date: Tue, 10 Feb 2026 01:50:33 +0100 Subject: [PATCH 175/234] ALICE3 Sensor orientation fix + first try to close in-stave gaps (#15043) --- .../ALICE3/TRK/simulation/src/Detector.cxx | 2 +- .../ALICE3/TRK/simulation/src/TRKLayer.cxx | 35 +++++++++++-------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx index e0fc6ef1ed35b..06fd2d9670b67 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx @@ -128,7 +128,7 @@ void Detector::buildTRKMiddleOuterLayers() LOGP(info, "TRKLayer created. Name: {}", GeometryTGeo::getTRKLayerPattern() + std::to_string(0)); mLayers.emplace_back(1, GeometryTGeo::getTRKLayerPattern() + std::to_string(1), 11.f, 10, 100.e-3); mLayers.emplace_back(2, GeometryTGeo::getTRKLayerPattern() + std::to_string(2), 15.f, 10, 100.e-3); - mLayers.emplace_back(3, GeometryTGeo::getTRKLayerPattern() + std::to_string(3), 19.f, 10, 100.e-3); + mLayers.emplace_back(3, GeometryTGeo::getTRKLayerPattern() + std::to_string(3), 20.f, 10, 100.e-3); mLayers.emplace_back(4, GeometryTGeo::getTRKLayerPattern() + std::to_string(4), 30.f, 10, 100.e-3); mLayers.emplace_back(5, GeometryTGeo::getTRKLayerPattern() + std::to_string(5), 45.f, 20, 100.e-3); mLayers.emplace_back(6, GeometryTGeo::getTRKLayerPattern() + std::to_string(6), 60.f, 20, 100.e-3); diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx index c4683f28918d0..8d30cf9759e40 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx @@ -168,7 +168,7 @@ TGeoVolume* TRKLayer::createChip(std::string type) TGeoVolume* TRKLayer::createModule(std::string type) { - TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); + TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); std::string moduleName = GeometryTGeo::getTRKModulePattern() + std::to_string(mLayerNumber); TGeoShape* module; @@ -176,7 +176,7 @@ TGeoVolume* TRKLayer::createModule(std::string type) if (type == "cylinder") { module = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, (constants::moduleMLOT::length * mNumberOfModules) / 2); - moduleVol = new TGeoVolume(moduleName.c_str(), module, medAir); + moduleVol = new TGeoVolume(moduleName.c_str(), module, medSi); TGeoVolume* chipVol = createChip("cylinder"); LOGP(debug, "Inserting {} in {} ", chipVol->GetName(), moduleVol->GetName()); @@ -186,7 +186,7 @@ TGeoVolume* TRKLayer::createModule(std::string type) double moduleLength = constants::moduleMLOT::length; module = new TGeoBBox(moduleWidth / 2, mChipThickness / 2, moduleLength / 2); // TO BE CHECKED !!! - moduleVol = new TGeoVolume(moduleName.c_str(), module, medAir); + moduleVol = new TGeoVolume(moduleName.c_str(), module, medSi); for (int iChip = 0; iChip < mHalfNumberOfChips; iChip++) { TGeoVolume* chipVolLeft = createChip("flat"); @@ -223,7 +223,7 @@ TGeoVolume* TRKLayer::createModule(std::string type) TGeoVolume* TRKLayer::createHalfStave(std::string type) { - TGeoMedium* medAir = gGeoManager->GetMedium("TRK_AIR$"); + TGeoMedium* medSi = gGeoManager->GetMedium("TRK_SILICON$"); std::string halfStaveName = GeometryTGeo::getTRKHalfStavePattern() + std::to_string(mLayerNumber); TGeoShape* halfStave; @@ -231,7 +231,7 @@ TGeoVolume* TRKLayer::createHalfStave(std::string type) if (type == "cylinder") { halfStave = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, mChipLength / 2); - halfStaveVol = new TGeoVolume(halfStaveName.c_str(), halfStave, medAir); + halfStaveVol = new TGeoVolume(halfStaveName.c_str(), halfStave, medSi); TGeoVolume* moduleVol = createModule("cylinder"); LOGP(debug, "Inserting {} in {} ", moduleVol->GetName(), halfStaveVol->GetName()); @@ -242,7 +242,7 @@ TGeoVolume* TRKLayer::createHalfStave(std::string type) double halfStaveLength = constants::moduleMLOT::length * mNumberOfModules; halfStave = new TGeoBBox(halfStaveWidth / 2, mChipThickness / 2, halfStaveLength / 2); - halfStaveVol = new TGeoVolume(halfStaveName.c_str(), halfStave, medAir); + halfStaveVol = new TGeoVolume(halfStaveName.c_str(), halfStave, medSi); for (int iModule = 0; iModule < mNumberOfModules; iModule++) { TGeoVolume* moduleVol = createModule("flat"); @@ -257,6 +257,9 @@ TGeoVolume* TRKLayer::createHalfStave(std::string type) halfStaveVol->AddNode(moduleVol, iModule, trans); } } + + halfStaveVol->SetLineColor(kYellow); + return halfStaveVol; } @@ -296,11 +299,11 @@ TGeoVolume* TRKLayer::createStave(std::string type) staveVol->AddNode(moduleVol, iModule, trans); } } else if (type == "staggered") { - /*double moduleWidth = constants::moduleMLOT::width; - double moduleLength = constants::moduleMLOT::length;*/ + double overlap = constants::moduleMLOT::gaps::outerEdgeLongSide + constants::moduleMLOT::chip::passiveEdgeReadOut + 0.1; // 1.5mm outer-edge + 1mm deadzone + 1mm (true)overlap + double shift = overlap / 2; - double halfstaveWidth = constants::ML::width; - double staveWidth = constants::OT::width; // Each stave has two modules (based on the LOI design) + double halfstaveWidth = constants::OT::halfstave::width; + double staveWidth = constants::OT::width - overlap; double staveLength = constants::moduleMLOT::length * mNumberOfModules; stave = new TGeoBBox(staveWidth / 2, mLogicalVolumeThickness / 2, staveLength / 2); @@ -311,12 +314,12 @@ TGeoVolume* TRKLayer::createStave(std::string type) TGeoVolume* halfStaveVolRight = createHalfStave("flat"); TGeoCombiTrans* transLeft = new TGeoCombiTrans(); - transLeft->SetTranslation(-halfstaveWidth / 2 + 0.05, 0, 0); // TO BE CHECKED !!! 1mm overlap between the modules + transLeft->SetTranslation(-halfstaveWidth / 2 + shift, 0, 0); // TO BE CHECKED !!! 1mm overlap between the modules LOGP(debug, "Inserting {} in {} ", halfStaveVolLeft->GetName(), staveVol->GetName()); staveVol->AddNode(halfStaveVolLeft, 0, transLeft); TGeoCombiTrans* transRight = new TGeoCombiTrans(); - transRight->SetTranslation(halfstaveWidth / 2 - 0.05, 0.2, 0); // TO BE CHECKED !!! 1mm overlap between the modules + transRight->SetTranslation(halfstaveWidth / 2 - shift, 0.2, 0); // TO BE CHECKED !!! 1mm overlap between the modules LOGP(debug, "Inserting {} in {} ", halfStaveVolRight->GetName(), staveVol->GetName()); staveVol->AddNode(halfStaveVolRight, 1, transRight); } else { @@ -377,7 +380,7 @@ void TRKLayer::createLayer(TGeoVolume* motherVolume) // Put the staves in the correct position and orientation TGeoCombiTrans* trans = new TGeoCombiTrans(); double theta = 360. * iStave / nStaves; - TGeoRotation* rot = new TGeoRotation("rot", theta + 90 + 3, 0, 0); + TGeoRotation* rot = new TGeoRotation("rot", theta - 90 + 3, 0, 0); trans->SetRotation(rot); trans->SetTranslation(mInnerRadius * std::cos(2. * TMath::Pi() * iStave / nStaves), mInnerRadius * std::sin(2 * TMath::Pi() * iStave / nStaves), 0); @@ -385,13 +388,15 @@ void TRKLayer::createLayer(TGeoVolume* motherVolume) layerVol->AddNode(staveVol, iStave, trans); } } else if (mLayout == kStaggered) { + double overlapInStave = constants::moduleMLOT::gaps::outerEdgeLongSide + constants::moduleMLOT::chip::passiveEdgeReadOut + 0.1; // 1.5mm outer-edge + 1mm deadzone + 1mm (true)overlap + double layerLength = constants::moduleMLOT::length * mNumberOfModules; + double staveWidth = constants::OT::width - overlapInStave; layer = new TGeoTube(mInnerRadius - 0.333 * layerThickness, mInnerRadius + 0.667 * layerThickness, layerLength / 2); layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); // Compute the number of staves - double staveWidth = constants::OT::width; // Each stave has two modules (based on the LOI design) int nStaves = (int)std::ceil(mInnerRadius * 2 * TMath::Pi() / staveWidth); nStaves += nStaves % 2; // Require an even number of staves @@ -410,7 +415,7 @@ void TRKLayer::createLayer(TGeoVolume* motherVolume) // Put the staves in the correct position and orientation TGeoCombiTrans* trans = new TGeoCombiTrans(); double theta = 360. * iStave / nStaves; - TGeoRotation* rot = new TGeoRotation("rot", theta + 90, 0, 0); + TGeoRotation* rot = new TGeoRotation("rot", theta - 90 + 3, 0, 0); trans->SetRotation(rot); trans->SetTranslation(mInnerRadius * std::cos(2. * TMath::Pi() * iStave / nStaves), mInnerRadius * std::sin(2 * TMath::Pi() * iStave / nStaves), 0); From d43ba29f8b05b6cb5e0914686830dd0740c87f80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ku=C4=8Dera?= <26327373+vkucera@users.noreply.github.com> Date: Thu, 5 Feb 2026 22:38:04 +0100 Subject: [PATCH 176/234] SimulationDataFormat: Delete unused files --- .../ProcessingEventInfo.h | 36 ------------------- 1 file changed, 36 deletions(-) delete mode 100644 DataFormats/simulation/include/SimulationDataFormat/ProcessingEventInfo.h diff --git a/DataFormats/simulation/include/SimulationDataFormat/ProcessingEventInfo.h b/DataFormats/simulation/include/SimulationDataFormat/ProcessingEventInfo.h deleted file mode 100644 index 150a8272c7714..0000000000000 --- a/DataFormats/simulation/include/SimulationDataFormat/ProcessingEventInfo.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ProcessingEventInfo.h -/// \brief Encapsulated meta information about current event being processed by FairRoot (analysis) tasks -/// \author Sandro Wenzel - -#ifndef ALICEO2_DATA_EVENTINFO_H_ -#define ALICEO2_DATA_EVENTINFO_H_ - -namespace o2 -{ - -// A class encapsulating meta information about events being process -// and the data being sent by run classes such as FairRunAna. -// Can be send to processing tasks for usage so that they do no longer -// need to access the FairRootManager directly. -struct ProcessingEventInfo { - double eventTime; //! time of the current event - int eventNumber; //! the current entry - int sourceNumber; //! the current source number - bool numberSources; //! number of sources - // can be extended further -}; - -} // namespace o2 - -#endif From 1f4624047d09e5bcf08c1e67c665593e4f178ef8 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Tue, 10 Feb 2026 10:50:56 +0100 Subject: [PATCH 177/234] Update OpenMP detection for macOS (#15040) Updated OpenMP detection for macOS with hints to brew library paths and set required compile flags. --- dependencies/FindOpenMPMacOS.cmake | 47 +++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/dependencies/FindOpenMPMacOS.cmake b/dependencies/FindOpenMPMacOS.cmake index 264ce5398a331..9bdeb35ecd46d 100644 --- a/dependencies/FindOpenMPMacOS.cmake +++ b/dependencies/FindOpenMPMacOS.cmake @@ -1,28 +1,53 @@ +# Copyright 2019-2026 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. + find_library(OpenMP_LIBRARY - NAMES omp + NAMES omp libomp + HINTS + /opt/homebrew/opt/libomp/lib + /usr/local/opt/libomp/lib ) find_path(OpenMP_INCLUDE_DIR - omp.h + NAMES omp.h + HINTS + /opt/homebrew/opt/libomp/include + /usr/local/opt/libomp/include ) mark_as_advanced(OpenMP_LIBRARY OpenMP_INCLUDE_DIR) include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(OpenMP DEFAULT_MSG - OpenMP_LIBRARY OpenMP_INCLUDE_DIR) +find_package_handle_standard_args( + OpenMPMacOS + DEFAULT_MSG + OpenMP_LIBRARY OpenMP_INCLUDE_DIR +) -if (OpenMP_FOUND) +if (OpenMPMacOS_FOUND) set(OpenMP_LIBRARIES ${OpenMP_LIBRARY}) set(OpenMP_INCLUDE_DIRS ${OpenMP_INCLUDE_DIR}) - set(OpenMP_COMPILE_OPTIONS -Xpreprocessor -fopenmp) - set(OpenMP_CXX_FOUND True) - set(OpenMPMacOS_FOUND True) - add_library(OpenMP::OpenMP_CXX SHARED IMPORTED) + set(OpenMP_CXX_FOUND TRUE) + set(OpenMP_FOUND TRUE) + + add_library(OpenMP::OpenMP_CXX INTERFACE IMPORTED) set_target_properties(OpenMP::OpenMP_CXX PROPERTIES - IMPORTED_LOCATION ${OpenMP_LIBRARIES} INTERFACE_INCLUDE_DIRECTORIES "${OpenMP_INCLUDE_DIRS}" - INTERFACE_COMPILE_OPTIONS "${OpenMP_COMPILE_OPTIONS}" + INTERFACE_COMPILE_OPTIONS "-Xclang;-fopenmp" + INTERFACE_LINK_LIBRARIES "${OpenMP_LIBRARIES}" + ) + message(STATUS + "Found OpenMP (macOS workaround): " + "library=${OpenMP_LIBRARY}, " + "include=${OpenMP_INCLUDE_DIR}" ) endif() From a63c9c11727258f79489f5dc8801a55a6483d7ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ku=C4=8Dera?= <26327373+vkucera@users.noreply.github.com> Date: Thu, 5 Feb 2026 22:53:21 +0100 Subject: [PATCH 178/234] TRD: Delete unused files --- .../TRD/base/src/CalSingleChamberStatus.cxx | 154 ------------------ 1 file changed, 154 deletions(-) delete mode 100644 Detectors/TRD/base/src/CalSingleChamberStatus.cxx diff --git a/Detectors/TRD/base/src/CalSingleChamberStatus.cxx b/Detectors/TRD/base/src/CalSingleChamberStatus.cxx deleted file mode 100644 index f054d49766461..0000000000000 --- a/Detectors/TRD/base/src/CalSingleChamberStatus.cxx +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/////////////////////////////////////////////////////////////////////////////// -// // -// Calibration base class for a single ROC // -// Contains one char value per pad // -// // -/////////////////////////////////////////////////////////////////////////////// - -#include "TRDBase/CalSingleChamberStatus.h" - -using namespace o2::trd; - -//_____________________________________________________________________________ -CalSingleChamberStatus::CalSingleChamberStatus() = default; - -//_____________________________________________________________________________ -CalSingleChamberStatus::CalSingleChamberStatus(Int_t p, Int_t c, Int_t cols) - : mPla(p), mCha(c), mNcols(cols) -{ - // - // Constructor that initializes a given pad plane type - // - - // - // The pad plane parameter - // - switch (p) { - case 0: - if (c == 2) { - // L0C0 type - mNrows = 12; - } else { - // L0C1 type - mNrows = 16; - } - break; - case 1: - if (c == 2) { - // L1C0 type - mNrows = 12; - } else { - // L1C1 type - mNrows = 16; - } - break; - case 2: - if (c == 2) { - // L2C0 type - mNrows = 12; - } else { - // L2C1 type - mNrows = 16; - } - break; - case 3: - if (c == 2) { - // L3C0 type - mNrows = 12; - } else { - // L3C1 type - mNrows = 16; - } - break; - case 4: - if (c == 2) { - // L4C0 type - mNrows = 12; - } else { - // L4C1 type - mNrows = 16; - } - break; - case 5: - if (c == 2) { - // L5C0 type - mNrows = 12; - } else { - // L5C1 type - mNrows = 16; - } - break; - }; - - mNchannels = mNrows * mNcols; - if (mNchannels != 0) { - mData.resize(mNchannels); - } - memset(&mData[0], 0, sizeof(mData[0]) * mData.size()); -} - -//_____________________________________________________________________________ -CalSingleChamberStatus::CalSingleChamberStatus(const CalSingleChamberStatus& c) - : mPla(c.mPla), mCha(c.mCha), mNrows(c.mNrows), mNcols(c.mNcols), mNchannels(c.mNchannels) -{ - // - // CalSingleChamberStatus copy constructor - // - - mData = c.mData; -} - -//_____________________________________________________________________________ -CalSingleChamberStatus::~CalSingleChamberStatus() = default; - -//_____________________________________________________________________________ -CalSingleChamberStatus& CalSingleChamberStatus::operator=(const CalSingleChamberStatus& c) -{ - // - // Assignment operator - // - - if (this == &c) { - return *this; - } - - mPla = c.mPla; - mCha = c.mCha; - mNrows = c.mNrows; - mNcols = c.mNcols; - mNchannels = c.mNchannels; - mData = c.mData; - - return *this; -} - -//_____________________________________________________________________________ -void CalSingleChamberStatus::Copy(CalSingleChamberStatus& c) const -{ - // - // Copy function - // - - Int_t iBin = 0; - - c.mPla = mPla; - c.mCha = mCha; - - c.mNrows = mNrows; - c.mNcols = mNcols; - - c.mNchannels = mNchannels; - - c.mData = mData; -} From d9bbbfccdc95fd9779cb9b08b7df78a8271e2565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ku=C4=8Dera?= <26327373+vkucera@users.noreply.github.com> Date: Thu, 5 Feb 2026 22:42:28 +0100 Subject: [PATCH 179/234] GlobalTrackingWorkflow: Delete unused files --- .../tofworkflow/src/RecoWorkflowSpec.cxx | 189 ------------------ 1 file changed, 189 deletions(-) delete mode 100644 Detectors/GlobalTrackingWorkflow/tofworkflow/src/RecoWorkflowSpec.cxx diff --git a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/RecoWorkflowSpec.cxx b/Detectors/GlobalTrackingWorkflow/tofworkflow/src/RecoWorkflowSpec.cxx deleted file mode 100644 index ab4f90464b31b..0000000000000 --- a/Detectors/GlobalTrackingWorkflow/tofworkflow/src/RecoWorkflowSpec.cxx +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "TOFWorkflow/RecoWorkflowSpec.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "Framework/DataProcessorSpec.h" -#include "Framework/DataRefUtils.h" -#include "Framework/Lifetime.h" -#include "Framework/Task.h" -#include "Framework/SerializationMethods.h" -#include "Headers/DataHeader.h" -#include "DataFormatsTOF/Cluster.h" -#include "GlobalTracking/MatchTOF.h" -#include "ReconstructionDataFormats/TrackTPCITS.h" -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GRPGeomHelper.h" -#include "CommonUtils/NameConf.h" -#include -#include "TStopwatch.h" -#include "TPCCalibration/VDriftHelper.h" - -// from FIT -#include "DataFormatsFT0/RecPoints.h" - -#include // for make_shared, make_unique, unique_ptr -#include - -using namespace o2::framework; - -namespace o2 -{ -namespace tof -{ - -// use the tasking system of DPL -// just need to implement 2 special methods init + run (there is no need to inherit from anything) -class TOFDPLRecoWorkflowTask -{ - using evIdx = o2::dataformats::EvIndex; - using MatchOutputType = std::vector; - - bool mUseMC = true; - bool mUseFIT = false; - - public: - explicit TOFDPLRecoWorkflowTask(std::shared_ptr gr, bool useMC, bool useFIT) : mGGCCDBRequest(gr), mUseMC(useMC), mUseFIT(useFIT) {} - - void init(framework::InitContext& ic) - { - o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); - mTimer.Stop(); - mTimer.Reset(); - } - - void run(framework::ProcessingContext& pc) - { - mTimer.Start(false); - updateTimeDependentParams(pc); - //>>>---------- attach input data --------------->>> - const auto clustersRO = pc.inputs().get>("tofcluster"); - const auto tracksRO = pc.inputs().get>("globaltrack"); - - if (mUseFIT) { - // Note: the particular variable will go out of scope, but the span is passed by copy to the - // worker and the underlying memory is valid throughout the whole computation - auto recPoints = std::move(pc.inputs().get>("fitrecpoints")); - mMatcher.setFITRecPoints(recPoints); - LOG(info) << "TOF Reco Workflow pulled " << recPoints.size() << " FIT RecPoints"; - } - - // we do a copy of the input but we are looking for a way to avoid it (current problem in conversion form unique_ptr to *) - - gsl::span itstpclab; - o2::dataformats::MCTruthContainer toflab; - if (mUseMC) { - const auto toflabel = pc.inputs().get*>("tofclusterlabel"); - itstpclab = pc.inputs().get>("itstpclabel"); - toflab = std::move(*toflabel); - } - - mMatcher.run(tracksRO, clustersRO, toflab, itstpclab); - - // in run_match_tof aggiugnere esplicitamente la chiamata a fill del tree (nella classe MatchTOF) e il metodo per leggere i vettori di output - - //... - // LOG(info) << "TOF CLUSTERER : TRANSFORMED " << digits->size() - // << " DIGITS TO " << mClustersArray.size() << " CLUSTERS"; - - // send matching-info - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MTC_ITSTPC", 0}, mMatcher.getMatchedTrackVector()); - if (mUseMC) { - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "MCMATCHTOF", 0}, mMatcher.getMatchedTOFLabelsVector()); - } - pc.outputs().snapshot(Output{o2::header::gDataOriginTOF, "CALIBDATA", 0}, mMatcher.getCalibVector()); - mTimer.Stop(); - } - - void endOfStream(EndOfStreamContext& ec) - { - LOGF(info, "TOF Matching total timing: Cpu: %.3e Real: %.3e s in %d slots", - mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); - } - - void updateTimeDependentParams(ProcessingContext& pc) - { - o2::base::GRPGeomHelper::instance().checkUpdates(pc); - mTPCVDriftHelper.extractCCDBInputs(pc); - static bool initOnceDone = false; - if (!initOnceDone) { // this params need to be queried only once - initOnceDone = true; - // put here init-once stuff - } - // we may have other params which need to be queried regularly - if (mTPCVDriftHelper.isUpdated()) { - LOGP(info, "Updating TPC fast transform map with new VDrift factor of {} wrt reference {} from source {}", - mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, mTPCVDriftHelper.getSourceName()); - mMatcher.setTPCVDrift(mTPCVDriftHelper.getVDriftObject()); - mTPCVDriftHelper.acknowledgeUpdate(); - } - } - - void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) - { - if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { - return; - } - if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) { - return; - } - } - - private: - o2::globaltracking::MatchTOF mMatcher; ///< Cluster finder - std::shared_ptr mGGCCDBRequest; - o2::tpc::VDriftHelper mTPCVDriftHelper{}; - TStopwatch mTimer; -}; - -o2::framework::DataProcessorSpec getTOFRecoWorkflowSpec(bool useMC, bool useFIT) -{ - std::vector inputs; - std::vector outputs; - inputs.emplace_back("tofcluster", o2::header::gDataOriginTOF, "CLUSTERS", 0, Lifetime::Timeframe); - inputs.emplace_back("globaltrack", "GLO", "TPCITS", 0, Lifetime::Timeframe); - if (useMC) { - inputs.emplace_back("tofclusterlabel", o2::header::gDataOriginTOF, "CLUSTERSMCTR", 0, Lifetime::Timeframe); - inputs.emplace_back("itstpclabel", "GLO", "TPCITS_MC", 0, Lifetime::Timeframe); - } - - if (useFIT) { - inputs.emplace_back("fitrecpoints", o2::header::gDataOriginFT0, "RECPOINTS", 0, Lifetime::Timeframe); - } - auto ggRequest = std::make_shared(false, // orbitResetTime - true, // GRPECS=true - false, // GRPLHCIF - true, // GRPMagField - true, // askMatLUT - o2::base::GRPGeomRequest::Aligned, // geometry - inputs, - true); - o2::tpc::VDriftHelper::requestCCDBInputs(inputs); - - outputs.emplace_back(o2::header::gDataOriginTOF, "MTC_ITSTPC", 0, Lifetime::Timeframe); - if (useMC) { - outputs.emplace_back(o2::header::gDataOriginTOF, "MCMATCHTOF", 0, Lifetime::Timeframe); - } - outputs.emplace_back(o2::header::gDataOriginTOF, "CALIBDATA", 0, Lifetime::Timeframe); - - return DataProcessorSpec{ - "TOFRecoWorkflow", - inputs, - outputs, - AlgorithmSpec{adaptFromTask(ggRequest, useMC, useFIT)}, - Options{ - {"material-lut-path", VariantType::String, "", {"Path of the material LUT file"}}}}; -} - -} // end namespace tof -} // end namespace o2 From aa7e258b79b263eff919e23579e9455ffe1c9c0b Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 9 Feb 2026 09:48:53 +0100 Subject: [PATCH 180/234] FindO2GPU.cmake: be less verbose --- dependencies/FindO2GPU.cmake | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/dependencies/FindO2GPU.cmake b/dependencies/FindO2GPU.cmake index 42d0162691c37..3e8f012fea4b5 100644 --- a/dependencies/FindO2GPU.cmake +++ b/dependencies/FindO2GPU.cmake @@ -10,7 +10,7 @@ # or submit itself to any jurisdiction. # NOTE!!!! - Whenever this file is changed, move it over to alidist/resources -# FindO2GPU.cmake Version 11 +# FindO2GPU.cmake Version 13 set(CUDA_COMPUTETARGET_DEFAULT_FULL 80-real 86-real 89-real 120-real 75-virtual) set(HIP_AMDGPUTARGET_DEFAULT_FULL gfx906;gfx908) @@ -65,7 +65,6 @@ function(detect_gpu_arch backend) # Detect GPU architecture, optionally filterri else() set(CUDA_TARGET TESLA) endif() - message(STATUS "Using optimized CUDA settings for ${CUDA_TARGET} GPU (sm_${CUDA_FIRST_TARGET})") string(REGEX MATCH "^[ \t\r\n]*gfx[0-9]+" HIP_FIRST_TARGET "${HIP_AMDGPUTARGET}") string(STRIP "${HIP_FIRST_TARGET}" HIP_FIRST_TARGET) @@ -87,12 +86,13 @@ function(detect_gpu_arch backend) # Detect GPU architecture, optionally filterri else() set(HIP_TARGET VEGA) endif() - message(STATUS "Using optimized HIP settings for ${HIP_TARGET} GPU (gfx${HIP_FIRST_TARGET})") if(backend STREQUAL "CUDA") # CUDA filter + message(STATUS "Using optimized CUDA settings for ${CUDA_TARGET} GPU (sm_${CUDA_FIRST_TARGET})") set(TARGET_ARCH "${CUDA_TARGET}" PARENT_SCOPE) elseif(backend STREQUAL "HIP") # HIP filter set(TARGET_ARCH "${HIP_TARGET}" PARENT_SCOPE) + message(STATUS "Using optimized HIP settings for ${HIP_TARGET} GPU (gfx${HIP_FIRST_TARGET})") elseif(backend STREQUAL "ALL" OR backend STREQUAL "AUTO") # Return all / enabled backends set(TARGET_ARCH) if(CUDA_ENABLED OR backend STREQUAL "ALL") @@ -194,8 +194,6 @@ if(ENABLE_CUDA) if(THRUST_INCLUDE_DIR STREQUAL "THRUST_INCLUDE_DIR-NOTFOUND") message(${FAILURE_SEVERITY} "CUDA found but thrust not available, looked under: ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}") set(CMAKE_CUDA_COMPILER OFF) - else() - message(STATUS "Thrust found in the path: ${THRUST_INCLUDE_DIR}") endif() if (NOT CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "12.8") message(${FAILURE_SEVERITY} "CUDA Version too old: ${CMAKE_CUDA_COMPILER_VERSION}, 12.8 required") @@ -278,15 +276,14 @@ if(ENABLE_OPENCL) AND NOT LLVM_SPIRV STREQUAL "LLVM_SPIRV-NOTFOUND" AND OPENCL_COMPATIBLE_CLANG_FOUND) set(OPENCL_ENABLED_SPIRV ON) - message(STATUS "Using CLANG ${LLVM_CLANG} and ${LLVM_SPIRV} for SPIR-V compilation") endif () if(OPENCL_COMPATIBLE_CLANG_FOUND AND (OpenCL_VERSION_STRING VERSION_GREATER_EQUAL 2.2 OR OPENCL_ENABLED_SPIRV)) set(OPENCL_ENABLED ON) - message(STATUS "Found OpenCL 2 (${OpenCL_VERSION_STRING} SPIR-V ${OPENCL_ENABLED_SPIRV} with CLANG ${LLVM_PACKAGE_VERSION})") + message(STATUS "Found OpenCL ${OpenCL_VERSION_STRING} (SPIR-V ${OPENCL_ENABLED_SPIRV} ${LLVM_CLANG} ${LLVM_PACKAGE_VERSION} ${LLVM_SPIRV})") elseif(NOT ENABLE_OPENCL STREQUAL "AUTO") - message(FATAL_ERROR "OpenCL 2.x not available") + message(FATAL_ERROR "OpenCL >= 2.x not available") else() set(OPENCL_ENABLED OFF) endif() @@ -347,7 +344,6 @@ if(ENABLE_HIP) set(CMAKE_HIP_HOST_COMPILER "$ENV{GCC_TOOLCHAIN_ROOT}/bin/gcc") endif() enable_language(HIP) - message(STATUS "HIP language enabled: ${CMAKE_HIP_COMPILER}") endif() elseif(NOT ENABLE_HIP STREQUAL "AUTO") message(FATAL_ERROR "HIP requested, but CMAKE_PREFIX_PATH env variable does not contain rocm folder!") @@ -373,7 +369,7 @@ if(ENABLE_HIP) if(HIP_AMDGPUTARGET) set(CMAKE_HIP_ARCHITECTURES "${HIP_AMDGPUTARGET}") endif() - message(STATUS "HIP Found (${hip_HIPCC_EXECUTABLE} version ${hip_VERSION}, Architectures ${CMAKE_HIP_ARCHITECTURES})") + message(STATUS "HIP Found (${hip_HIPCC_EXECUTABLE} version ${hip_VERSION}, ${CMAKE_HIP_COMPILER}, Architectures ${CMAKE_HIP_ARCHITECTURES})") else() set(HIP_ENABLED OFF) endif() From 2d96089c502e6c582a108e4a0f0ed1cbb7a21e69 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Mon, 9 Feb 2026 09:49:15 +0100 Subject: [PATCH 181/234] GPU Parameters: Add script to generate parameter file from parameter list csv/json and architecture --- GPU/GPUTracking/CMakeLists.txt | 4 +- .../gpu_param_header_generator.cmake | 4 +- .../Standalone/Benchmark/CMakeLists.txt | 2 + GPU/GPUTracking/Standalone/CMakeLists.txt | 1 - .../Standalone/tools/dumpGPUParamByArch.sh | 60 +++++++++++++++++++ GPU/GPUTracking/display/CMakeLists.txt | 9 ++- .../display/filterMacros/setinclude.sh.in | 2 +- 7 files changed, 72 insertions(+), 10 deletions(-) rename GPU/GPUTracking/{cmake => Definitions/Parameters}/gpu_param_header_generator.cmake (96%) create mode 100755 GPU/GPUTracking/Standalone/tools/dumpGPUParamByArch.sh diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index 082dc1f10b1d6..dfee81b398a79 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -292,10 +292,10 @@ foreach(GPU_PARAM_JSON_FILE IN LISTS GPU_PARAM_JSON) math(EXPR GPU_PARAM_JSON_N_FILES "${GPU_PARAM_JSON_N_FILES} + 1") endforeach() -include(cmake/gpu_param_header_generator.cmake) +include(Definitions/Parameters/gpu_param_header_generator.cmake) set(GPU_DEFAULT_PARAMS_HEADER ${ON_THE_FLY_DIR}/GPUDefParametersDefaults.h) set(GPU_DEFAULT_PARAMS_HEADER_DEVICE ${ON_THE_FLY_DIR}/GPUDefParametersDefaultsDevice.h) -generate_gpu_param_header("${GPU_PARAM_JSON_FILES}" "ALL" "${GPU_DEFAULT_PARAMS_HEADER}" "${GPU_DEFAULT_PARAMS_HEADER_DEVICE}" GPU_CONST_PARAM_ARCHITECTUES) # generate header with default GPU parameters, arch selected by CMake variables +generate_gpu_param_header("${GPU_PARAM_JSON_FILES}" "ALL" "${GPU_DEFAULT_PARAMS_HEADER}" "${GPU_DEFAULT_PARAMS_HEADER_DEVICE}" GPU_CONST_PARAM_ARCHITECTUES) # generate header with default GPU parameters for all architectures list(APPEND GENERATED_HEADERS_LIST ${GPU_DEFAULT_PARAMS_HEADER} ${GPU_DEFAULT_PARAMS_HEADER_DEVICE}) set(HDRS_INSTALL ${HDRS_INSTALL} ${GENERATED_HEADERS_LIST}) diff --git a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake b/GPU/GPUTracking/Definitions/Parameters/gpu_param_header_generator.cmake similarity index 96% rename from GPU/GPUTracking/cmake/gpu_param_header_generator.cmake rename to GPU/GPUTracking/Definitions/Parameters/gpu_param_header_generator.cmake index 383d194aaa717..d0e36e7f15026 100644 --- a/GPU/GPUTracking/cmake/gpu_param_header_generator.cmake +++ b/GPU/GPUTracking/Definitions/Parameters/gpu_param_header_generator.cmake @@ -110,6 +110,9 @@ function(generate_gpu_param_header GPU_PARAM_JSON_FILES ARCH_LIST OUT_HEADER OUT string(APPEND TMP_HEADER_DEVICE "#if 0\n") foreach(ARCH IN LISTS ARCH_LIST) + if(do_all_architectures EQUAL -1 AND do_auto_architectures EQUAL -1 AND NOT generate_gpu_param_header_OUTPUT_TMP_${ARCH}) + message(FATAL_ERROR "No parameters defined for architecture ${ARCH}") + endif() string(APPEND TMP_HEADER_DEVICE "\n#elif defined(GPUCA_GPUTYPE_${ARCH})\n") string(APPEND TMP_HEADER_DEVICE ${generate_gpu_param_header_OUTPUT_TMP_${ARCH}}) endforeach() @@ -129,5 +132,4 @@ function(generate_gpu_param_header GPU_PARAM_JSON_FILES ARCH_LIST OUT_HEADER OUT string(APPEND TMP_HEADER_DEVICE "\n#endif // GPUDEFPARAMETERSDEFAULTSDEVICE_H\n") file(GENERATE OUTPUT "${OUT_HEADER}" CONTENT "${TMP_HEADER}") file(GENERATE OUTPUT "${OUT_HEADER_DEVICE}" CONTENT "${TMP_HEADER_DEVICE}") - message(STATUS "Generated ${OUT_HEADER} and ${OUT_HEADER_DEVICE}") endfunction() diff --git a/GPU/GPUTracking/Standalone/Benchmark/CMakeLists.txt b/GPU/GPUTracking/Standalone/Benchmark/CMakeLists.txt index eeafcfc44142d..9f28fd8cc6fe9 100644 --- a/GPU/GPUTracking/Standalone/Benchmark/CMakeLists.txt +++ b/GPU/GPUTracking/Standalone/Benchmark/CMakeLists.txt @@ -30,6 +30,8 @@ if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") target_link_libraries(${targetName} PUBLIC GPUTracking) endif() +install(DIRECTORY ../tools DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/GPU) +install(DIRECTORY ../../Definitions/Parameters/ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/GPU/tools FILES_MATCHING REGEX "\\.(python|sh|cmake)") target_compile_definitions(${targetName} PRIVATE $) if(ROOT_FOUND) diff --git a/GPU/GPUTracking/Standalone/CMakeLists.txt b/GPU/GPUTracking/Standalone/CMakeLists.txt index 48fbd77c62786..0cf72fd2b4c3e 100644 --- a/GPU/GPUTracking/Standalone/CMakeLists.txt +++ b/GPU/GPUTracking/Standalone/CMakeLists.txt @@ -246,4 +246,3 @@ install(TARGETS ca TPCFastTransformation standalone_support) install(FILES "cmake/makefile" DESTINATION "${CMAKE_INSTALL_PREFIX}") install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${O2_DIR} ${CMAKE_INSTALL_PREFIX}/src)") install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_BINARY_DIR}/config.cmake ${CMAKE_INSTALL_PREFIX}/config.cmake)") -install(DIRECTORY tools DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/GPU) diff --git a/GPU/GPUTracking/Standalone/tools/dumpGPUParamByArch.sh b/GPU/GPUTracking/Standalone/tools/dumpGPUParamByArch.sh new file mode 100755 index 0000000000000..0a4f5f5c1656f --- /dev/null +++ b/GPU/GPUTracking/Standalone/tools/dumpGPUParamByArch.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +if [[ -z $3 ]]; then + echo "Usage: dumpGPUParamByArch.sh [JSON or CSV parameter file] [Architecture] [Output File]" + exit 1 +fi + +if ! command -v root &> /dev/null; then + echo "Cannot run root, please make sure ROOT is available and in the parh" + exit 1 +fi + +if [[ ! -f $1 ]]; then + echo "Input file $1 does not exist" + exit 1 +fi + +if [[ -f "include/GPU/GPUDefParametersLoad.inc" ]]; then + LOADDIR=$(realpath "include/GPU") +elif [[ -f "$O2_ROOT/include/GPU/GPUDefParametersLoad.inc" ]]; then + LOADDIR=$(realpath "$O2_ROOT/include/GPU/") +else + echo "Cannot find GPUDefParametersLoad.inc, please run from standalone benchmark folder or set \$O2_ROOT to the standalone or O2 installation" + exit 1 +fi + +set -e + +TMPDIR=$(mktemp -d) +if [[ $? != 0 ]]; then + echo "Failed to create a temporary directory" + exit 1 +fi + +BASE_DIR=$(dirname $(realpath ${BASH_SOURCE[0]})) + +if [[ $1 =~ \.csv$ ]]; then + "${BASE_DIR}"/../../Definitions/Parameters/csv_to_json.sh $1 > "$TMPDIR"/temp.json + JSON_FILE="$TMPDIR"/temp.json +else + JSON_FILE=$(realpath $1) +fi + +cat < "${TMPDIR}"/CMakeLists.txt +cmake_minimum_required(VERSION 3.16 FATAL_ERROR) +project(DumpGPUParam NONE) +include($BASE_DIR/../../Definitions/Parameters/gpu_param_header_generator.cmake) +generate_gpu_param_header("${JSON_FILE}" "$2" "${TMPDIR}/GPUDefParametersDefaultsOnTheFly.h" "${TMPDIR}/GPUDefParametersDefaultsDeviceOnTheFly.h") +EOT + +cmake -B "${TMPDIR}" -S"${TMPDIR}" + +echo -e "#define GPUCA_GPUTYPE_$2\n" \ + "#define PARAMETER_FILE \"${TMPDIR}/GPUDefParametersDefaultsOnTheFly.h\"\n" \ + "gInterpreter->AddIncludePath(\"${TMPDIR}\");gInterpreter->AddIncludePath(\"${LOADDIR}\");\n" \ + ".x $BASE_DIR/dumpGPUDefParam.C(\"$3\")\n.q\n" | root -l -b + +echo -e "\nCreated $3 with parameters for $2 architecture from $1" + +rm -Rf "${TMPDIR}" diff --git a/GPU/GPUTracking/display/CMakeLists.txt b/GPU/GPUTracking/display/CMakeLists.txt index 32d25ee08b729..82ce0d4a9b190 100644 --- a/GPU/GPUTracking/display/CMakeLists.txt +++ b/GPU/GPUTracking/display/CMakeLists.txt @@ -151,14 +151,13 @@ if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") add_library(O2::${MODULE} ALIAS ${MODULE}) target_link_libraries(${targetName} PUBLIC O2::GPUTracking) install(TARGETS ${MODULE}) - - install(DIRECTORY filterMacros/ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/GPU/displayTrackFilter FILES_MATCHING PATTERN "*.C") - get_property(GPU_DISPLAY_INCLUDE_PATH DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES) - configure_file(filterMacros/setinclude.sh.in setinclude.sh @ONLY) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/setinclude.sh PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/GPU/displayTrackFilter) endif() install(FILES ${HDRS} ${HDRS_INSTALL} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/GPU) +install(DIRECTORY filterMacros/ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/GPU/displayTrackFilter FILES_MATCHING PATTERN "*.C") +get_property(GPU_DISPLAY_INCLUDE_PATH DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES) +configure_file(filterMacros/setinclude.sh.in setinclude.sh @ONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/setinclude.sh PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/GPU/displayTrackFilter) target_compile_definitions(${targetName} PRIVATE $) diff --git a/GPU/GPUTracking/display/filterMacros/setinclude.sh.in b/GPU/GPUTracking/display/filterMacros/setinclude.sh.in index c588923db4b43..0a301537bba0e 100755 --- a/GPU/GPUTracking/display/filterMacros/setinclude.sh.in +++ b/GPU/GPUTracking/display/filterMacros/setinclude.sh.in @@ -1,2 +1,2 @@ #!/bin/bash -export ROOC_INCLUDE_PATH="@GPU_DISPLAY_INCLUDE_PATH@" +export ROOT_INCLUDE_PATH="@GPU_DISPLAY_INCLUDE_PATH@" From bf8a4027b3eb50ce57d54dc0b796afa1cb6a2fcf Mon Sep 17 00:00:00 2001 From: David Rohr Date: Tue, 10 Feb 2026 14:21:16 +0100 Subject: [PATCH 182/234] Fix codechecker violation --- Detectors/EMCAL/base/src/ClusterFactory.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Detectors/EMCAL/base/src/ClusterFactory.cxx b/Detectors/EMCAL/base/src/ClusterFactory.cxx index 970f7979ef86d..1752e5c0e98ee 100644 --- a/Detectors/EMCAL/base/src/ClusterFactory.cxx +++ b/Detectors/EMCAL/base/src/ClusterFactory.cxx @@ -528,8 +528,9 @@ void ClusterFactory::evalNExMax(gsl::span inputsIndices, A // loop over all other cells in cluster for (size_t j = 0; j < n; j++) { - if (i == j) + if (i == j) { continue; + } // adjacent cell is any cell with adjacent phi or eta index if (std::abs(rows[i] - rows[j]) <= 1 && From f10bf6ecd0328e6a96700cc6de8d1afd57e66875 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Wed, 11 Feb 2026 10:02:55 +0100 Subject: [PATCH 183/234] DPL: oldest possible timeframe triggered CompletionPolicy (#15046) This will trigger the processing whenever a given slot will not receive data anymore in virtue of its timeslice being past the oldest possible timeframe. --- .../Framework/CompletionPolicyHelpers.h | 8 ++++- .../Core/src/CompletionPolicyHelpers.cxx | 29 ++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Framework/Core/include/Framework/CompletionPolicyHelpers.h b/Framework/Core/include/Framework/CompletionPolicyHelpers.h index 7f77e4a96f76f..9fce626854e5b 100644 --- a/Framework/Core/include/Framework/CompletionPolicyHelpers.h +++ b/Framework/Core/include/Framework/CompletionPolicyHelpers.h @@ -1,4 +1,4 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// Copyright 2019-2026 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. // @@ -54,6 +54,12 @@ struct CompletionPolicyHelpers { } static CompletionPolicy consumeWhenAny(std::string matchName); + // Consume all the data captured until the oldest possible timeframe + // in input indicates that nothing else can be added to this timeslice. + // Useful in case of wildcards which multiplex multiple subspecs on the + // same input. + static CompletionPolicy consumeWhenPastOldestPossibleTimeframe(const char* name, CompletionPolicy::Matcher matcher); + /// When any of the parts of the record have been received, consume them. static CompletionPolicy consumeWhenAnyWithAllConditions(const char* name, CompletionPolicy::Matcher matcher); /// Default matcher applies for all devices diff --git a/Framework/Core/src/CompletionPolicyHelpers.cxx b/Framework/Core/src/CompletionPolicyHelpers.cxx index 67c726b7f4368..2b49b8dfa9acd 100644 --- a/Framework/Core/src/CompletionPolicyHelpers.cxx +++ b/Framework/Core/src/CompletionPolicyHelpers.cxx @@ -1,4 +1,4 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// Copyright 2019-2026 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. // @@ -11,6 +11,7 @@ #include "Framework/CompletionPolicyHelpers.h" #include "Framework/CompletionPolicy.h" +#include "Framework/DataProcessingHeader.h" #include "Framework/InputSpan.h" #include "Framework/DeviceSpec.h" #include "Framework/CompilerBuiltins.h" @@ -263,6 +264,32 @@ CompletionPolicy CompletionPolicyHelpers::consumeWhenAnyZeroCount(const char* na return CompletionPolicy{name, matcher, callback, false}; } +CompletionPolicy CompletionPolicyHelpers::consumeWhenPastOldestPossibleTimeframe(const char* name, CompletionPolicy::Matcher matcher) +{ + auto callback = [](InputSpan const& inputs, std::vector const&, ServiceRegistryRef& ref) -> CompletionPolicy::CompletionOp { + size_t currentTimeslice = -1; + for (auto& input : inputs) { + if (input.header == nullptr) { + continue; + } + o2::framework::DataProcessingHeader const* dph = o2::header::get(input.header); + if (dph && !TimingInfo::timesliceIsTimer(dph->startTime)) { + currentTimeslice = dph->startTime; + break; + } + } + + auto& timesliceIndex = ref.get(); + auto oldestPossibleTimeslice = timesliceIndex.getOldestPossibleInput().timeslice.value; + + if (currentTimeslice >= oldestPossibleTimeslice) { + return CompletionPolicy::CompletionOp::Retry; + } + return CompletionPolicy::CompletionOp::Consume; + }; + return CompletionPolicy{name, matcher, callback, false}; +} + CompletionPolicy CompletionPolicyHelpers::consumeWhenAny(const char* name, CompletionPolicy::Matcher matcher) { auto callback = [](InputSpan const& inputs, std::vector const&, ServiceRegistryRef& ref) -> CompletionPolicy::CompletionOp { From 331f2cc815bd213df04c40ecb9359422f11edd8d Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Wed, 11 Feb 2026 11:18:17 +0100 Subject: [PATCH 184/234] fix topology adjust corner case (#15053) --- Framework/Core/src/ArrowSupport.cxx | 4 +++- run/o2sim_kine_publisher.cxx | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Framework/Core/src/ArrowSupport.cxx b/Framework/Core/src/ArrowSupport.cxx index 31cddc9803d69..450f31f4ba7d3 100644 --- a/Framework/Core/src/ArrowSupport.cxx +++ b/Framework/Core/src/ArrowSupport.cxx @@ -581,7 +581,6 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() auto spawner = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-spawner"); }); auto analysisCCDB = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-ccdb"); }); auto builder = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-index-builder"); }); - auto reader = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-reader"); }); auto writer = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-writer"); }); auto& dec = ctx.services().get(); dec.requestedAODs.clear(); @@ -659,6 +658,9 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() workflow.erase(writer); } + // removing writer would invalidate the reader iterator if it was created before + auto reader = std::ranges::find_if(workflow, [](DataProcessorSpec const& spec) { return spec.name.starts_with("internal-dpl-aod-reader"); }); + if (reader != workflow.end()) { // If reader and/or builder were adjusted, remove unneeded outputs // update currently requested AODs diff --git a/run/o2sim_kine_publisher.cxx b/run/o2sim_kine_publisher.cxx index f72dd6eebaaf0..cfbea6ae02a5f 100644 --- a/run/o2sim_kine_publisher.cxx +++ b/run/o2sim_kine_publisher.cxx @@ -13,7 +13,6 @@ #include "Framework/AnalysisTask.h" #include "Monitoring/Monitoring.h" #include "Framework/CommonDataProcessors.h" -#include "SimulationDataFormat/MCTrack.h" #include "Steer/MCKinematicsReader.h" #include "Framework/runDataProcessing.h" @@ -64,6 +63,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) spec.outputs.emplace_back("MC", "MCHEADER", 0, Lifetime::Timeframe); spec.outputs.emplace_back("MC", "MCTRACKS", 0, Lifetime::Timeframe); spec.requiredServices.push_back(o2::framework::ArrowSupport::arrowBackendSpec()); - spec.algorithm = CommonDataProcessors::wrapWithRateLimiting(spec.algorithm); + spec.algorithm = CommonDataProcessors::wrapWithTimesliceConsumption(spec.algorithm); return {spec}; } From 970ed8ea7328d3828694ba4770429ea680ff2524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Piero=C5=BCak?= <94726725+wpierozak@users.noreply.github.com> Date: Wed, 11 Feb 2026 14:41:38 +0100 Subject: [PATCH 185/234] EventsPerBC calibration task for FT0 (O2-6563) (#14986) Implements the EventsPerBC calibration task for FT0, which generates a histogram of VTX events above a defined amplitude threshold plotted against the BC. * FT0: created first sketch of implementation of generation of TVX per Event calibration object * FT0: Updated CMakeLists for calibration * FT0: Added missing entry in FT0CalibrationLinkDef.h * FT0 calibration: fixed ROOT directory compilation, fixed CCDB output * FT0: refined logs in EventsPerBc calibration, fixed setting TF info in run method * FT0: Added readme to calibrations * FT0: Changed calibration object name, implemented missing OrbitReset fetching * FT0 EventsPerBc calibration: storing histograms in float format, updated readme * Changed type of EventsPerBc calibration object to std::array * FT0: corrected macro FT0readEventsPerBc, corrected typo in calibration README * Created CCDB object class for EvetnsPerBC calibration * FT0: formatted EvensPerBc.h * FT0: removed amplitudes thresholds from EventsPerBc * FT0: Removed from EventsPerBc calibarion option to define slot lenght in TFs; Small code cleaning * Changed default value of min number of entries in EventsPerBcProcessor from 5000 to 5000u --- DataFormats/Detectors/FIT/FT0/CMakeLists.txt | 1 + .../FT0/include/DataFormatsFT0/EventsPerBc.h | 25 ++++ .../FIT/FT0/src/DataFormatsFT0LinkDef.h | 2 + Detectors/FIT/FT0/calibration/CMakeLists.txt | 70 ++++++---- Detectors/FIT/FT0/calibration/README.md | 62 +++++++++ .../FT0Calibration/EventsPerBcCalibrator.h | 81 ++++++++++++ .../calibration/src/EventsPerBcCalibrator.cxx | 81 ++++++++++++ .../calibration/src/FT0CalibrationLinkDef.h | 4 +- .../FT0EventsPerBcProcessor-Workflow.cxx | 47 +++++++ .../calibration/workflow/FT0EventsPerBcSpec.h | 124 ++++++++++++++++++ Detectors/FIT/FT0/macros/CMakeLists.txt | 19 ++- Detectors/FIT/FT0/macros/FT0readEventsPerBc.C | 52 ++++++++ 12 files changed, 538 insertions(+), 30 deletions(-) create mode 100644 DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/EventsPerBc.h create mode 100644 Detectors/FIT/FT0/calibration/README.md create mode 100644 Detectors/FIT/FT0/calibration/include/FT0Calibration/EventsPerBcCalibrator.h create mode 100644 Detectors/FIT/FT0/calibration/src/EventsPerBcCalibrator.cxx create mode 100644 Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcProcessor-Workflow.cxx create mode 100644 Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcSpec.h create mode 100644 Detectors/FIT/FT0/macros/FT0readEventsPerBc.C diff --git a/DataFormats/Detectors/FIT/FT0/CMakeLists.txt b/DataFormats/Detectors/FIT/FT0/CMakeLists.txt index e5331b7b739b2..f7d6a111f4348 100644 --- a/DataFormats/Detectors/FIT/FT0/CMakeLists.txt +++ b/DataFormats/Detectors/FIT/FT0/CMakeLists.txt @@ -47,4 +47,5 @@ o2_target_root_dictionary(DataFormatsFT0 include/DataFormatsFT0/GlobalOffsetsCalibrationObject.h include/DataFormatsFT0/SpectraInfoObject.h include/DataFormatsFT0/SlewingCoef.h + include/DataFormatsFT0/EventsPerBc.h ) diff --git a/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/EventsPerBc.h b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/EventsPerBc.h new file mode 100644 index 0000000000000..9fcd1318914bd --- /dev/null +++ b/DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/EventsPerBc.h @@ -0,0 +1,25 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef _FT0_EVENTS_PER_BC_CALIB_OBJECT +#define _FT0_EVENTS_PER_BC_CALIB_OBJECT + +#include "CommonConstants/LHCConstants.h" +#include + +namespace o2::ft0 +{ +struct EventsPerBc { + std::array histogram; + ClassDefNV(EventsPerBc, 1); +}; +} // namespace o2::ft0 +#endif \ No newline at end of file diff --git a/DataFormats/Detectors/FIT/FT0/src/DataFormatsFT0LinkDef.h b/DataFormats/Detectors/FIT/FT0/src/DataFormatsFT0LinkDef.h index 0d3491224180c..7f8c17a0cd191 100644 --- a/DataFormats/Detectors/FIT/FT0/src/DataFormatsFT0LinkDef.h +++ b/DataFormats/Detectors/FIT/FT0/src/DataFormatsFT0LinkDef.h @@ -56,4 +56,6 @@ #pragma link C++ class std::pair < std::vector < double>, std::vector < double>> + ; #pragma link C++ class o2::ft0::SlewingCoef + ; +#pragma link C++ class o2::ft0::EventsPerBc + ; + #endif diff --git a/Detectors/FIT/FT0/calibration/CMakeLists.txt b/Detectors/FIT/FT0/calibration/CMakeLists.txt index d103b4a9a18b6..bee0493d300c1 100644 --- a/Detectors/FIT/FT0/calibration/CMakeLists.txt +++ b/Detectors/FIT/FT0/calibration/CMakeLists.txt @@ -10,26 +10,50 @@ # or submit itself to any jurisdiction. o2_add_library(FT0Calibration - SOURCES - src/FT0TimeOffsetSlotContainer.cxx - PUBLIC_LINK_LIBRARIES - O2::DataFormatsFT0 - O2::CommonDataFormat - O2::DetectorsCalibration - ) - o2_target_root_dictionary(FT0Calibration - HEADERS - include/FT0Calibration/FT0TimeOffsetSlotContainer.h - ) - o2_add_executable(ft0-time-offset-calib - COMPONENT_NAME calibration - SOURCES workflow/FT0TimeOffsetCalibration-Workflow.cxx - PUBLIC_LINK_LIBRARIES - O2::FT0Calibration O2::FITCalibration - ) - o2_add_executable(ft0-time-spectra-processor - COMPONENT_NAME calibration - SOURCES workflow/FT0TimeSpectraProcessor-Workflow.cxx - PUBLIC_LINK_LIBRARIES - O2::FT0Calibration - ) + SOURCES + src/FT0TimeOffsetSlotContainer.cxx + src/EventsPerBcCalibrator.cxx + PUBLIC_LINK_LIBRARIES + O2::DetectorsCalibration + O2::Framework + O2::CommonUtils + Microsoft.GSL::GSL + O2::DataFormatsFT0 + O2::CommonDataFormat + O2::Steer + O2::CCDB + ROOT::Minuit + ROOT::Hist + ) + +o2_target_root_dictionary(FT0Calibration + HEADERS + include/FT0Calibration/FT0TimeOffsetSlotContainer.h + include/FT0Calibration/EventsPerBcCalibrator.h + ) + +o2_add_executable(ft0-time-offset-calib + COMPONENT_NAME calibration + SOURCES + workflow/FT0TimeOffsetCalibration-Workflow.cxx + PUBLIC_LINK_LIBRARIES + O2::FT0Calibration O2::FITCalibration + ) + +o2_add_executable(ft0-time-spectra-processor + COMPONENT_NAME calibration + SOURCES + workflow/FT0TimeSpectraProcessor-Workflow.cxx + PUBLIC_LINK_LIBRARIES + O2::FT0Calibration + ) + +o2_add_executable(ft0-events-per-bc-processor + COMPONENT_NAME calibration + SOURCES + workflow/FT0EventsPerBcProcessor-Workflow.cxx + PUBLIC_LINK_LIBRARIES + O2::FT0Calibration + O2::Framework + O2::CCDB +) \ No newline at end of file diff --git a/Detectors/FIT/FT0/calibration/README.md b/Detectors/FIT/FT0/calibration/README.md new file mode 100644 index 0000000000000..78b0f980400d2 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/README.md @@ -0,0 +1,62 @@ +# Calibrations + +## Events per BC Calibration +### Description +Generates histograms of **Events per Bunch Crossing (BC)**. Events can be filtered by applying amplitude thresholds to the **A-side** and **C-side**. + +### Command-Line Options +| Option | Default | Description | +| :--- | :--- | :--- | +| `--slot-len-sec` | `3600` | Duration of each slot in seconds. | +| `--slot-len-tf` | `0` | Slot length in Time Frames (TFs). | +| `--one-object-per-run` | — | If set, the workflow creates only one calibration object per run. | +| `--min-entries-number` | `0` | Minimum number of entries required for a slot to be valid. | +| `--min-ampl-side-a` | `-2147483648` | Amplitude threshold for Side A events. | +| `--min-ampl-side-c` | `-2147483648` | Amplitude threshold for Side C events. | + +--- + +## How to Run + +### Simulation Data +First, it is important to digitize data with a non-zero run number, orbit, and timestamp. To set these parameters, one can use the `--configKeyValues` option, as shown in the example below. +``` +o2-sim-digitizer-workflow \ +--onlyDet FT0 \ +--configKeyValues="HBFUtils.nHBFPerTF=128;HBFUtils.orbitFirst=128;HBFUtils.orbitFirstSampled=256;HBFUtils.runNumber=560560;HBFUtils.startTime=1768464099000" +``` + +To process simulation data, digits must first be converted to RAW format. The `o2-ft0-digi2raw` tool performs this conversion and generates the required configuration file. + +Once converted, you can run the calibration either as a single integrated workflow or by spawning as the sender and receiver components separately. + +#### Single Workflow Example +Execute the following command within the simulation directory: +``` +o2-raw-file-reader-workflow --input-conf FT0raw.cfg --loop -1 \ +| o2-ft0-flp-dpl-workflow --condition-backend=http://localhost:8080 \ +| o2-calibration-ft0-events-per-bc-processor --FT0EventsPerBcProcessor "--slot-len-sec=10" \ +| o2-calibration-ccdb-populator-workflow --ccdb-path=http://localhost:8080 +``` + +Sender example (in simulation directory): +``` +o2-raw-file-reader-workflow --input-conf FT0raw.cfg --loop -1 \ +| o2-ft0-flp-dpl-workflow --condition-backend=http://localhost:8080 \ +| o2-dpl-output-proxy --channel-config "name=downstream,method=connect,address=tcp://localhost:30453,type=push,transport=zeromq" --dataspec "downstream:FT0/DIGITSBC" +``` + +Receiver example: +``` +o2-dpl-raw-proxy --channel-config "name=readout-proxy,type=pull,method=bind,address=tcp://localhost:30453,rateLogging=1,transport=zeromq" --dataspec "A:FT0/DIGITSBC/0" \ +| o2-calibration-ft0-events-per-bc-processor --FT0EventsPerBcProcessor "--slot-len-sec=10 --min-ampl-side-a=0" \ +| o2-calibration-ccdb-populator-workflow --ccdb-path=http://localhost:8080/ +``` + +### CTF Data +Example: +``` +o2-ctf-reader-workflow --ctf-input ctf.root --onlyDet FT0 \ +| o2-calibration-ft0-events-per-bc-processor --FT0EventsPerBcProcessor "--slot-len-sec=10" \ +| o2-calibration-ccdb-populator-workflow --ccdb-path=http://localhost:8080/ +``` \ No newline at end of file diff --git a/Detectors/FIT/FT0/calibration/include/FT0Calibration/EventsPerBcCalibrator.h b/Detectors/FIT/FT0/calibration/include/FT0Calibration/EventsPerBcCalibrator.h new file mode 100644 index 0000000000000..f44824517f258 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/include/FT0Calibration/EventsPerBcCalibrator.h @@ -0,0 +1,81 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_FT0TVXPERBCID +#define O2_FT0TVXPERBCID + +#include +#include +#include +#include + +#include "CommonDataFormat/FlatHisto2D.h" +#include "CommonConstants/LHCConstants.h" +#include "DataFormatsFT0/SpectraInfoObject.h" +#include "DataFormatsFT0/Digit.h" +#include "DataFormatsFT0/EventsPerBc.h" +#include "DetectorsCalibration/TimeSlotCalibration.h" +#include "DetectorsCalibration/TimeSlot.h" +#include "CommonDataFormat/TFIDInfo.h" +#include "TH1F.h" +#include "Rtypes.h" + +namespace o2::ft0 +{ +struct EventsPerBcContainer { + EventsPerBcContainer(int32_t minAmplitudeSideA, int32_t minAmplitudeSideC) : mMinAmplitudeSideA(minAmplitudeSideA), mMinAmplitudeSideC(minAmplitudeSideC) {} + + size_t getEntries() const { return entries; } + void print() const; + void fill(const o2::dataformats::TFIDInfo& ti, const gsl::span data); + void merge(const EventsPerBcContainer* prev); + + const int32_t mMinAmplitudeSideA; + const int32_t mMinAmplitudeSideC; + + std::array mTvx{0.0}; + size_t entries{0}; + long startTimeStamp{0}; + long stopTimeStamp{0}; + + ClassDefNV(EventsPerBcContainer, 1); +}; + +class EventsPerBcCalibrator final : public o2::calibration::TimeSlotCalibration +{ + using Slot = o2::calibration::TimeSlot; + using TFType = o2::calibration::TFType; + using EventsHistogram = std::array; + + public: + EventsPerBcCalibrator(uint32_t minNumberOfEntries, int32_t minAmplitudeSideA, int32_t minAmplitudeSideC); + + bool hasEnoughData(const Slot& slot) const override; + void initOutput() override; + void finalizeSlot(Slot& slot) override; + Slot& emplaceNewSlot(bool front, TFType tstart, TFType tend) override; + + const std::vector& getTvxPerBc() { return mTvxPerBcs; } + std::vector>& getTvxPerBcCcdbInfo() { return mTvxPerBcInfos; } + + private: + const uint32_t mMinNumberOfEntries; + const int32_t mMinAmplitudeSideA; + const int32_t mMinAmplitudeSideC; + + std::vector mTvxPerBcs; + std::vector> mTvxPerBcInfos; + + ClassDefOverride(EventsPerBcCalibrator, 1); +}; +} // namespace o2::ft0 + +#endif diff --git a/Detectors/FIT/FT0/calibration/src/EventsPerBcCalibrator.cxx b/Detectors/FIT/FT0/calibration/src/EventsPerBcCalibrator.cxx new file mode 100644 index 0000000000000..a2230f51dc4ea --- /dev/null +++ b/Detectors/FIT/FT0/calibration/src/EventsPerBcCalibrator.cxx @@ -0,0 +1,81 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FT0Calibration/EventsPerBcCalibrator.h" +#include "CommonUtils/MemFileHelper.h" + +namespace o2::ft0 +{ +void EventsPerBcContainer::print() const +{ + LOG(info) << entries << " entries"; +} + +void EventsPerBcContainer::fill(const o2::dataformats::TFIDInfo& ti, const gsl::span data) +{ + size_t oldEntries = entries; + for (const auto& digit : data) { + if (digit.mTriggers.getVertex() && digit.mTriggers.getAmplA() >= mMinAmplitudeSideA && digit.mTriggers.getAmplC() >= mMinAmplitudeSideC) { + mTvx[digit.mIntRecord.bc]++; + entries++; + } + } + LOG(debug) << "Container is filled with " << entries - oldEntries << " new events"; +} + +void EventsPerBcContainer::merge(const EventsPerBcContainer* prev) +{ + for (int bc = 0; bc < o2::constants::lhc::LHCMaxBunches; bc++) { + mTvx[bc] += prev->mTvx[bc]; + } + entries += prev->entries; +} + +void EventsPerBcCalibrator::initOutput() +{ + mTvxPerBcs.clear(); + mTvxPerBcInfos.clear(); +} + +EventsPerBcCalibrator::EventsPerBcCalibrator(uint32_t minNumberOfEntries, int32_t minAmplitudeSideA, int32_t minAmplitudeSideC) : mMinNumberOfEntries(minNumberOfEntries), mMinAmplitudeSideA(minAmplitudeSideA), mMinAmplitudeSideC(minAmplitudeSideC) +{ + LOG(info) << "Defined threshold for number of entires per slot: " << mMinNumberOfEntries; + LOG(info) << "Defined threshold for side A amplitude for event: " << mMinAmplitudeSideA; + LOG(info) << "Defined threshold for side C amplitude for event: " << mMinAmplitudeSideC; +} + +bool EventsPerBcCalibrator::hasEnoughData(const EventsPerBcCalibrator::Slot& slot) const +{ + return slot.getContainer()->entries > mMinNumberOfEntries; +} + +void EventsPerBcCalibrator::finalizeSlot(EventsPerBcCalibrator::Slot& slot) +{ + LOG(info) << "Finalizing slot from " << slot.getStartTimeMS() << " to " << slot.getEndTimeMS(); + o2::ft0::EventsPerBcContainer* data = slot.getContainer(); + mTvxPerBcs.emplace_back(data->mTvx); + + auto clName = o2::utils::MemFileHelper::getClassName(mTvxPerBcs.back()); + auto flName = o2::ccdb::CcdbApi::generateFileName(clName); + + std::map metaData; + mTvxPerBcInfos.emplace_back(std::make_unique("FT0/Calib/EventsPerBc", clName, flName, metaData, slot.getStartTimeMS(), slot.getEndTimeMS())); + LOG(info) << "Created object valid from " << mTvxPerBcInfos.back()->getStartValidityTimestamp() << " to " << mTvxPerBcInfos.back()->getEndValidityTimestamp(); +} + +EventsPerBcCalibrator::Slot& EventsPerBcCalibrator::emplaceNewSlot(bool front, TFType tstart, TFType tend) +{ + auto& cont = getSlots(); + auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); + slot.setContainer(std::make_unique(mMinAmplitudeSideA, mMinAmplitudeSideC)); + return slot; +} +} // namespace o2::ft0 \ No newline at end of file diff --git a/Detectors/FIT/FT0/calibration/src/FT0CalibrationLinkDef.h b/Detectors/FIT/FT0/calibration/src/FT0CalibrationLinkDef.h index 49f72e8cbdfff..11b1ce25e9353 100644 --- a/Detectors/FIT/FT0/calibration/src/FT0CalibrationLinkDef.h +++ b/Detectors/FIT/FT0/calibration/src/FT0CalibrationLinkDef.h @@ -16,7 +16,9 @@ #pragma link off all functions; #pragma link C++ class o2::ft0::FT0TimeOffsetSlotContainer + ; +#pragma link C++ class o2::ft0::EventsPerBcCalibrator + ; #pragma link C++ class o2::calibration::TimeSlot < o2::ft0::FT0TimeOffsetSlotContainer>; #pragma link C++ class o2::calibration::TimeSlotCalibration < o2::ft0::FT0TimeOffsetSlotContainer>; - +#pragma link C++ class o2::calibration::TimeSlot < o2::ft0::EventsPerBcContainer> + ; +#pragma link C++ class o2::calibration::TimeSlotCalibration < o2::ft0::EventsPerBcContainer> + ; #endif diff --git a/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcProcessor-Workflow.cxx b/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcProcessor-Workflow.cxx new file mode 100644 index 0000000000000..ac7a8e52f53b1 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcProcessor-Workflow.cxx @@ -0,0 +1,47 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "FT0EventsPerBcSpec.h" +#include "Framework/Lifetime.h" +#include + +o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext const& cfgc) +{ + using namespace o2::framework; + using o2::calibration::FT0EventsPerBcProcessor; + std::vector inputs; + inputs.emplace_back("digits", "FT0", "DIGITSBC", Lifetime::Timeframe); + auto ccdbRequest = std::make_shared(true, // orbitResetTime + false, // GRPECS=true + false, // GRPLHCIF + false, // GRPMagField + false, // askMatLUT + o2::base::GRPGeomRequest::None, // geometry + inputs); + std::vector outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "EventsPerBc"}, Lifetime::Timeframe); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "EventsPerBc"}, Lifetime::Timeframe); + DataProcessorSpec dataProcessorSpec{ + "FT0EventsPerBcProcessor", + inputs, + outputs, + AlgorithmSpec(adaptFromTask(ccdbRequest)), + Options{ + {"slot-len-sec", VariantType::UInt32, 3600u, {"Duration of each slot in seconds"}}, + {"one-object-per-run", VariantType::Bool, false, {"If set, workflow creates only one calibration object per run"}}, + {"min-entries-number", VariantType::UInt32, 5000u, {"Minimum number of entries required for a slot to be valid"}}, + {"min-ampl-side-a", VariantType::Int, 0, {"Amplitude threshold for Side A events"}}, + {"min-ampl-side-c", VariantType::Int, 0, {"Amplitude threshold for Side C events"}}}}; + + WorkflowSpec workflow; + workflow.emplace_back(dataProcessorSpec); + return workflow; +} \ No newline at end of file diff --git a/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcSpec.h b/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcSpec.h new file mode 100644 index 0000000000000..c587ab58fcd90 --- /dev/null +++ b/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcSpec.h @@ -0,0 +1,124 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_CALIBRATION_FT0_EVENTS_PER_BC_CALIBRATOR_H +#define O2_CALIBRATION_FT0_EVENTS_PER_BC_CALIBRATOR_H + +#include "Framework/runDataProcessing.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" +#include +#include "Framework/DeviceSpec.h" +#include "Framework/WorkflowSpec.h" +#include "Framework/Task.h" +#include "DetectorsCalibration/Utils.h" +#include "DetectorsBase/GRPGeomHelper.h" + +#include "DataFormatsFT0/Digit.h" +#include "FT0Calibration/EventsPerBcCalibrator.h" + +namespace o2::calibration +{ +class FT0EventsPerBcProcessor final : public o2::framework::Task +{ + public: + FT0EventsPerBcProcessor(std::shared_ptr request) : mCCDBRequest(request) {} + + void init(o2::framework::InitContext& ic) final + { + o2::base::GRPGeomHelper::instance().setRequest(mCCDBRequest); + if (ic.options().hasOption("slot-len-sec")) { + mSlotLenSec = ic.options().get("slot-len-sec"); + } + if (ic.options().hasOption("one-object-per-run")) { + mOneObjectPerRun = ic.options().get("one-object-per-run"); + } + if (ic.options().hasOption("min-entries-number")) { + mMinNumberOfEntries = ic.options().get("min-entries-number"); + } + if (ic.options().hasOption("min-ampl-side-a")) { + mMinAmplitudeSideA = ic.options().get("min-ampl-side-a"); + } + if (ic.options().hasOption("min-ampl-side-c")) { + mMinAmplitudeSideC = ic.options().get("min-ampl-side-c"); + } + + mCalibrator = std::make_unique(mMinNumberOfEntries, mMinAmplitudeSideA, mMinAmplitudeSideC); + + if (mOneObjectPerRun) { + LOG(info) << "Only one object will be created at the end of run"; + mCalibrator->setUpdateAtTheEndOfRunOnly(); + } + if (mOneObjectPerRun == false) { + LOG(info) << "Defined slot interval to " << mSlotLenSec << " seconds"; + mCalibrator->setSlotLengthInSeconds(mSlotLenSec); + } + } + + void finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) + { + o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj); + } + + void run(o2::framework::ProcessingContext& pc) final + { + o2::base::GRPGeomHelper::instance().checkUpdates(pc); + auto digits = pc.inputs().get>("digits"); + o2::base::TFIDInfoHelper::fillTFIDInfo(pc, mCalibrator->getCurrentTFInfo()); + if (digits.size() == 0) { + return; + } + mCalibrator->process(digits); + if (mOneObjectPerRun == false) { + sendOutput(pc.outputs()); + } + } + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + LOG(info) << "Received end-of-stream, checking for slot to finalize..."; + mCalibrator->checkSlotsToFinalize(); + sendOutput(ec.outputs()); + mCalibrator->initOutput(); + } + + void sendOutput(o2::framework::DataAllocator& output) + { + using o2::framework::Output; + const auto& tvxHists = mCalibrator->getTvxPerBc(); + auto& infos = mCalibrator->getTvxPerBcCcdbInfo(); + for (unsigned int idx = 0; idx < tvxHists.size(); idx++) { + auto& info = infos[idx]; + const auto& payload = tvxHists[idx]; + + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, info.get()); + LOG(info) << "Sending object " << info->getPath() << "/" << info->getFileName() << " of size " << image->size() + << " bytes, valid for " << info->getStartValidityTimestamp() << " : " << info->getEndValidityTimestamp(); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "EventsPerBc", idx}, *image.get()); + output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, "EventsPerBc", idx}, *info.get()); + } + + if (tvxHists.size()) { + mCalibrator->initOutput(); + } + } + + private: + std::shared_ptr mCCDBRequest; + std::unique_ptr mCalibrator; + bool mOneObjectPerRun; + uint32_t mSlotLenSec; + uint32_t mMinNumberOfEntries; + int32_t mMinAmplitudeSideA; + int32_t mMinAmplitudeSideC; +}; +} // namespace o2::calibration +#endif \ No newline at end of file diff --git a/Detectors/FIT/FT0/macros/CMakeLists.txt b/Detectors/FIT/FT0/macros/CMakeLists.txt index c4ed27d2513ba..17491ca4962c1 100644 --- a/Detectors/FIT/FT0/macros/CMakeLists.txt +++ b/Detectors/FIT/FT0/macros/CMakeLists.txt @@ -1,14 +1,21 @@ -# Copyright CERN and copyright holders of ALICE O2. This software is distributed -# under the terms of the GNU General Public License v3 (GPL Version 3), copied -# verbatim in the file "COPYING". +# 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. # -# See http://alice-o2.web.cern.ch/license for full licensing information. +# 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. +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. o2_add_test_root_macro(FT0Misaligner.C PUBLIC_LINK_LIBRARIES O2::CCDB O2::FT0Simulation LABELS ft0) + +o2_add_test_root_macro(FT0readEventsPerBc.C + PUBLIC_LINK_LIBRARIES + O2::CCDB + O2::DataFormatsFT0 + LABELS ft0) diff --git a/Detectors/FIT/FT0/macros/FT0readEventsPerBc.C b/Detectors/FIT/FT0/macros/FT0readEventsPerBc.C new file mode 100644 index 0000000000000..c6afc86389b9b --- /dev/null +++ b/Detectors/FIT/FT0/macros/FT0readEventsPerBc.C @@ -0,0 +1,52 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include +#include +#endif + +#include "CCDB/CcdbApi.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "TH1F.h" +#include "DataFormatsFT0/EventsPerBc.h" +#include "Framework/Logger.h" +#include "CommonConstants/LHCConstants.h" + +std::unique_ptr hist; +std::unique_ptr canvas; + +void FT0readEventsPerBc(std::string ccdbUrl, long timestamp) +{ + o2::ccdb::CcdbApi ccdbApi; + ccdbApi.init(ccdbUrl); + const std::string ccdbPath = "FT0/Calib/EventsPerBc"; + std::map metadata; + + if (timestamp < 0) { + timestamp = o2::ccdb::getCurrentTimestamp(); + } + + std::unique_ptr events(ccdbApi.retrieveFromTFileAny(ccdbPath, metadata, timestamp)); + + if (!events) { + LOGP(fatal, "EventsPerBc object not found in {}/{} for timestamp {}.", ccdbUrl, ccdbPath, timestamp); + return; + } + + hist = std::make_unique("eventsPerBcHist", "Events per BC", o2::constants::lhc::LHCMaxBunches, 0, o2::constants::lhc::LHCMaxBunches - 1); + for (int idx = 0; idx < o2::constants::lhc::LHCMaxBunches; idx++) { + hist->Fill(idx, events->histogram[idx]); + } + canvas = std::make_unique(); + hist->Draw(); + canvas->Draw(); +} \ No newline at end of file From 8d3541adfc2ff3fb78615f86cc2a234eb8bd60a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ku=C4=8Dera?= <26327373+vkucera@users.noreply.github.com> Date: Thu, 5 Feb 2026 23:27:12 +0100 Subject: [PATCH 186/234] Vertexing: Delete unused files --- .../DetectorsVertexing/FwdDCAFitterN.h | 1297 ----------------- Detectors/Vertexing/src/FwdDCAFitterN.cxx | 33 - 2 files changed, 1330 deletions(-) delete mode 100644 Detectors/Vertexing/include/DetectorsVertexing/FwdDCAFitterN.h delete mode 100644 Detectors/Vertexing/src/FwdDCAFitterN.cxx diff --git a/Detectors/Vertexing/include/DetectorsVertexing/FwdDCAFitterN.h b/Detectors/Vertexing/include/DetectorsVertexing/FwdDCAFitterN.h deleted file mode 100644 index d5bc6631575af..0000000000000 --- a/Detectors/Vertexing/include/DetectorsVertexing/FwdDCAFitterN.h +++ /dev/null @@ -1,1297 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file FwdDCAFitterN.h -/// \brief Defintions for N-prongs secondary vertex fit -/// \author ruben.shahoyan@cern.ch, adapted from central barrel to fwd rapidities by Rita Sadek, rita.sadek@cern.ch -/// For the formulae derivation see /afs/cern.ch/user/s/shahoian/public/O2/DCAFitter/DCAFitterN.pdf - -#ifndef _ALICEO2_DCA_FWDFITTERN_ -#define _ALICEO2_DCA_FWDFITTERN_ -#include -#include "MathUtils/Cartesian.h" -#include "ReconstructionDataFormats/TrackFwd.h" -#include "ReconstructionDataFormats/Track.h" -#include "ReconstructionDataFormats/HelixHelper.h" -#include -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" - -namespace o2 -{ -namespace vertexing -{ - -///__________________________________________________________________________________ -///< Fwd Inverse cov matrix (augmented by a dummy Z error) of the point defined by the track -struct FwdTrackCovI { - float sxx, syy, sxy, szz; - - FwdTrackCovI(const o2::track::TrackParCovFwd& trc, float zerrFactor = 1.) { set(trc, zerrFactor); } - FwdTrackCovI() = default; - void set(const o2::track::TrackParCovFwd& trc, float zerrFactor = 1) - { - float cxx = trc.getSigma2X(), cyy = trc.getSigma2Y(), cxy = trc.getSigmaXY(), czz = cyy * zerrFactor; - float detXY = cxx * cyy - cxy * cxy; - if (detXY > 0.) { - auto detXYI = 1. / detXY; - sxx = cyy * detXYI; - syy = cxx * detXYI; - sxy = -cxy * detXYI; - szz = 1. / czz; - } else { - throw std::runtime_error("invalid track covariance"); - } - } -}; - -///__________________________________________________________________________ -///< Fwd derivative (up to 2) of the TrackParam position over its running param Z -struct FwdTrackDeriv { - float dxdz, dydz, d2xdz2, d2ydz2; - FwdTrackDeriv() = default; - FwdTrackDeriv(const o2::track::TrackParFwd& trc, float bz) { set(trc, bz); } - void set(const o2::track::TrackParFwd& trc, float bz) - { - float snp = trc.getSnp(), csp = std::sqrt((1. - snp) * (1. + snp)), cspI = 1. / csp, crv2c = trc.getCurvature(bz), tgl = trc.getTanl(), tglI = 1. / tgl; - if (crv2c == 0.) { - crv2c = (trc.getCharge()) * 0.3 * bz * (-1e-3); - } - - dxdz = csp * tglI; - dydz = snp * tglI; - d2xdz2 = crv2c * snp * tglI * tglI; - d2ydz2 = -crv2c * csp * tglI * tglI; - } -}; - -template -class FwdDCAFitterN -{ - static constexpr double NMin = 2; - static constexpr double NMax = 4; - static constexpr double NInv = 1. / N; - static constexpr int MAXHYP = 2; - static constexpr float ZerrFactor = 5.; // factor for conversion of track covXX to dummy covZZ - using Track = o2::track::TrackParCovFwd; - using TrackAuxPar = o2::track::TrackAuxPar; - using CrossInfo = o2::track::CrossInfo; - using Vec3D = ROOT::Math::SVector; - using VecND = ROOT::Math::SVector; - using MatSym3D = ROOT::Math::SMatrix>; - using MatStd3D = ROOT::Math::SMatrix>; - using MatSymND = ROOT::Math::SMatrix>; - using MatStdND = ROOT::Math::SMatrix>; - using SMatrix55 = ROOT::Math::SMatrix>; - using TrackCoefVtx = MatStd3D; - using ArrTrack = std::array; // container for prongs (tracks) at single vertex cand. - using ArrTrackCovI = std::array; // container for inv.cov.matrices at single vertex cand. - using ArrTrCoef = std::array; // container of TrackCoefVtx coefficients at single vertex cand. - using ArrTrDer = std::array; // container of Track 1st and 2nd derivative over their Z param - using ArrTrPos = std::array; // container of Track positions - - public: - static constexpr int getNProngs() { return N; } - - FwdDCAFitterN() = default; - FwdDCAFitterN(float bz, bool useAbsDCA, bool prop2DCA) : mBz(bz), mUseAbsDCA(useAbsDCA), mPropagateToPCA(prop2DCA) - { - static_assert(N >= NMin && N <= NMax, "N prongs outside of allowed range"); - } - - //========================================================================= - ///< return PCA candidate, by default best on is provided (no check for the index validity) - const Vec3D& getPCACandidate(int cand = 0) const { return mPCA[mOrder[cand]]; } - const auto getPCACandidatePos(int cand = 0) const - { - const auto& vd = mPCA[mOrder[cand]]; - return std::array{float(vd[0]), float(vd[1]), float(vd[2])}; - } - - ///< return Chi2 at PCA candidate (no check for its validity) - float getChi2AtPCACandidate(int cand = 0) const { return mChi2[mOrder[cand]]; } - - ///< prepare copies of tracks at the V0 candidate (no check for the candidate validity) - /// must be called before getTrack(i,cand) query - bool FwdpropagateTracksToVertex(int cand = 0); - - ///< check if propagation of tracks to candidate vertex was done - bool isPropagateTracksToVertexDone(int cand = 0) const { return mTrPropDone[mOrder[cand]]; } - - ///< track param propagated to V0 candidate (no check for the candidate validity) - /// propagateTracksToVertex must be called in advance - Track& getTrack(int i, int cand = 0) - { - if (!mTrPropDone[mOrder[cand]]) { - throw std::runtime_error("propagateTracksToVertex was not called yet"); - } - return mCandTr[mOrder[cand]][i]; - } - - ///< calculate on the fly track param (no cov mat) at candidate - o2::track::TrackParFwd FwdgetTrackParamAtPCA(int i, int cand = 0) const; - - MatSym3D calcPCACovMatrix(int cand = 0) const; - - std::array calcPCACovMatrixFlat(int cand = 0) const - { - auto m = calcPCACovMatrix(cand); - return {float(m(0, 0)), float(m(1, 0)), float(m(1, 1)), float(m(2, 0)), float(m(2, 1)), float(m(2, 2))}; - } - - const Track* getOrigTrackPtr(int i) const { return mOrigTrPtr[i]; } - - ///< return number of iterations during minimization (no check for its validity) - int getNIterations(int cand = 0) const { return mNIters[mOrder[cand]]; } - void setPropagateToPCA(bool v = true) { mPropagateToPCA = v; } - void setMaxIter(int n = 60) { mMaxIter = n > 2 ? n : 2; } - void setMaxR(float r = 200.) { mMaxR2 = r * r; } - void setMaxDXIni(float d = 4.) { mMaxDXIni = d; } - void setMaxChi2(float chi2 = 999.) { mMaxChi2 = chi2; } - void setBz(float bz) { mBz = std::abs(bz) > o2::constants::math::Almost0 ? bz : 0.f; } - void setMinParamChange(float x = 1e-3) { mMinParamChange = x > 1e-4 ? x : 1.e-4; } - void setMinRelChi2Change(float r = 0.9) { mMinRelChi2Change = r > 0.1 ? r : 999.; } - void setUseAbsDCA(bool v) { mUseAbsDCA = v; } - void setMatLUT(const o2::base::MatLayerCylSet* m) - { - mMatLUT = m; - mUseMatBudget = true; - } - void setTGeoMat(bool v = true) { mTGeoFallBackAllowed = v; } - void setMaxDistance2ToMerge(float v) { mMaxDist2ToMergeSeeds = v; } - - int getNCandidates() const { return mCurHyp; } - int getMaxIter() const { return mMaxIter; } - float getMaxR() const { return std::sqrt(mMaxR2); } - float getMaxDXIni() const { return mMaxDXIni; } - float getMaxChi2() const { return mMaxChi2; } - float getMinParamChange() const { return mMinParamChange; } - float getBz() const { return mBz; } - double getK(double b) const { return std::abs(o2::constants::math::B2C * b); } - double getHz(double b) const { return std::copysign(1, b); } - - float getMaxDistance2ToMerge() const { return mMaxDist2ToMergeSeeds; } - bool getUseAbsDCA() const { return mUseAbsDCA; } - bool getPropagateToPCA() const { return mPropagateToPCA; } - - template - int process(const Tr&... args); - void print() const; - - protected: - bool FwdcalcPCACoefs(); - bool FwdcalcInverseWeight(); - void FwdcalcResidDerivatives(); - void FwdcalcResidDerivativesNoErr(); - void FwdcalcChi2Derivatives(); - void FwdcalcChi2DerivativesNoErr(); - void FwdcalcPCA(); - void FwdcalcPCANoErr(); - void FwdcalcTrackResiduals(); - void calcTrackDerivatives(); - float findZatXY(int cand = 0); - void findZatXY_mid(int cand = 0); - void findZatXY_lineApprox(int cand = 0); - void findZatXY_quad(int cand = 0); - void findZatXY_linear(int cand = 0); - double FwdcalcChi2() const; - double FwdcalcChi2NoErr() const; - bool FwdcorrectTracks(const VecND& corrZ); - bool minimizeChi2(); - bool minimizeChi2NoErr(); - bool roughDXCut() const; - bool closerToAlternative() const; - static double getAbsMax(const VecND& v); - bool propagateToVtx(o2::track::TrackParCovFwd& t, const std::array& p, const std::array& cov) const; - - ///< track param positions at V0 candidate (no check for the candidate validity) - const Vec3D& getTrackPos(int i, int cand = 0) const { return mTrPos[mOrder[cand]][i]; } - - ///< track Z-param at V0 candidate (no check for the candidate validity) - float getTrackZ(int i, int cand = 0) const { return getTrackPos(i, cand)[2]; } - - MatStd3D getTrackRotMatrix(int i) const // generate 3D matrix for track rotation to global frame - // no rotation for fwd: mat=I - { - MatStd3D mat; - mat(0, 0) = 1; - mat(1, 1) = 1; - mat(2, 2) = 1; - return mat; - } - - MatSym3D getTrackCovMatrix(int i, int cand = 0) const // generate covariance matrix of track position, adding fake Z error - { - const auto& trc = mCandTr[mOrder[cand]][i]; - MatSym3D mat; - mat(0, 0) = trc.getSigma2X(); - mat(1, 1) = trc.getSigma2Y(); - mat(1, 0) = trc.getSigmaXY(); - mat(2, 2) = trc.getSigma2Y() * ZerrFactor; - return mat; - } - - void assign(int) {} - template - void assign(int i, const T& t, const Tr&... args) - { - static_assert(std::is_convertible(), "Wrong track type"); - mOrigTrPtr[i] = &t; - assign(i + 1, args...); - } - - void clear() - { - mCurHyp = 0; - mAllowAltPreference = true; - } - - static void setTrackPos(Vec3D& pnt, const Track& tr) - { - pnt[0] = tr.getX(); - pnt[1] = tr.getY(); - pnt[2] = tr.getZ(); - } - - private: - // vectors of 1st derivatives of track local residuals over Z parameters - std::array, N> mDResidDz; - // vectors of 1nd derivatives of track local residuals over Z parameters - std::array, N> mD2ResidDz2; - VecND mDChi2Dz; // 1st derivatives of chi2 over tracks Z params - MatSymND mD2Chi2Dz2; // 2nd derivatives of chi2 over tracks Z params (symmetric matrix) - - std::array mOrigTrPtr; - std::array mTrAux; // Aux track info for each track at each cand. vertex - CrossInfo mCrossings; // info on track crossing - - std::array mTrcEInv; // errors for each track at each cand. vertex - std::array mCandTr; // tracks at each cond. vertex (Note: Errors are at seed XY point) - std::array mTrCFVT; // TrackCoefVtx for each track at each cand. vertex - std::array mTrDer; // Track derivativse - std::array mTrPos; // Track positions - std::array mTrRes; // Track residuals - std::array mPCA; // PCA for each vertex candidate - std::array mChi2 = {0}; // Chi2 at PCA candidate - std::array mNIters; // number of iterations for each seed - std::array mTrPropDone; // Flag that the tracks are fully propagated to PCA - MatSym3D mWeightInv; // inverse weight of single track, [sum{M^T E M}]^-1 in EQ.T - std::array mOrder{0}; - int mCurHyp = 0; - int mCrossIDCur = 0; - int mCrossIDAlt = -1; - bool mAllowAltPreference = true; // if the fit converges to alternative PCA seed, abandon the current one - bool mUseAbsDCA = false; // use abs. distance minimization rather than chi2 - bool mPropagateToPCA = true; // create tracks version propagated to PCA - bool mUseMatBudget = false; // include MCS effects in track propagation - bool mTGeoFallBackAllowed = true; // use TGeo for precise estimate of mat. budget - int mMaxIter = 60; // max number of iterations - float mBz = 0; // bz field, to be set by user - float mMaxR2 = 200. * 200.; // reject PCA's above this radius - float mMaxDXIni = 4.; // reject (if>0) PCA candidate if tracks DZ exceeds threshold - float mMinParamChange = 1e-5; // stop iterations if largest change of any X is smaller than this - float mMinRelChi2Change = 0.98; // stop iterations is chi2/chi2old > this - float mMaxChi2 = 100; // abs cut on chi2 or abs distance - float mMaxDist2ToMergeSeeds = 1.; // merge 2 seeds to their average if their distance^2 is below the threshold - const o2::base::MatLayerCylSet* mMatLUT = nullptr; // use to compute material budget to include MCS effects - - ClassDefNV(FwdDCAFitterN, 1); -}; - -///_________________________________________________________________________ -template -template -int FwdDCAFitterN::process(const Tr&... args) -{ - - static_assert(sizeof...(args) == N, "incorrect number of input tracks"); - assign(0, args...); - clear(); - - for (int i = 0; i < N; i++) { - mTrAux[i].set(*mOrigTrPtr[i], mBz); - } - - if (!mCrossings.set(mTrAux[0], *mOrigTrPtr[0], mTrAux[1], *mOrigTrPtr[1])) { // even for N>2 it should be enough to test just 1 loop - return 0; // no crossing - } - - if (mCrossings.nDCA == MAXHYP) { // if there are 2 candidates - auto dst2 = (mCrossings.xDCA[0] - mCrossings.xDCA[1]) * (mCrossings.xDCA[0] - mCrossings.xDCA[1]) + - (mCrossings.yDCA[0] - mCrossings.yDCA[1]) * (mCrossings.yDCA[0] - mCrossings.yDCA[1]); - - if (dst2 < mMaxDist2ToMergeSeeds) { - mCrossings.nDCA = 1; - mCrossings.xDCA[0] = 0.5 * (mCrossings.xDCA[0] + mCrossings.xDCA[1]); - mCrossings.yDCA[0] = 0.5 * (mCrossings.yDCA[0] + mCrossings.yDCA[1]); - } - } - - // check all crossings - for (int ic = 0; ic < mCrossings.nDCA; ic++) { - // check if radius is acceptable - if (mCrossings.xDCA[ic] * mCrossings.xDCA[ic] + mCrossings.yDCA[ic] * mCrossings.yDCA[ic] > mMaxR2) { - continue; - } - - mCrossIDCur = ic; - mCrossIDAlt = (mCrossings.nDCA == 2 && mAllowAltPreference) ? 1 - ic : -1; // works for max 2 crossings - mNIters[mCurHyp] = 0; - mTrPropDone[mCurHyp] = false; - mChi2[mCurHyp] = -1.; - - findZatXY_mid(mCurHyp); - - if (mUseAbsDCA ? minimizeChi2NoErr() : minimizeChi2()) { - mOrder[mCurHyp] = mCurHyp; - if (mPropagateToPCA && !FwdpropagateTracksToVertex(mCurHyp)) { - continue; - } - mCurHyp++; - } - } - - for (int i = mCurHyp; i--;) { // order in quality - for (int j = i; j--;) { - if (mChi2[mOrder[i]] < mChi2[mOrder[j]]) { - std::swap(mOrder[i], mOrder[j]); - } - } - } - - return mCurHyp; -} - -//__________________________________________________________________________ -template -bool FwdDCAFitterN::FwdcalcPCACoefs() -{ - //< calculate Ti matrices for global vertex decomposition to V = sum_{0 -bool FwdDCAFitterN::FwdcalcInverseWeight() -{ - //< calculate [sum_{0 -void FwdDCAFitterN::FwdcalcResidDerivatives() -{ - //< calculate matrix of derivatives for weighted chi2: residual i vs parameter Z of track j - MatStd3D matMT; - for (int i = N; i--;) { // residual being differentiated - // const auto& taux = mTrAux[i]; - for (int j = N; j--;) { // track over which we differentiate - const auto& matT = mTrCFVT[mCurHyp][j]; // coefficient matrix for track J - const auto& trDz = mTrDer[mCurHyp][j]; // track point derivs over track Z param - auto& dr1 = mDResidDz[i][j]; - auto& dr2 = mD2ResidDz2[i][j]; - // calculate M_i^transverse * T_j , M_i^transverse=I -> MT=T - matMT[0][0] = matT[0][0]; - matMT[0][1] = matT[0][1]; - matMT[0][2] = matT[0][2]; - matMT[1][0] = matT[1][0]; - matMT[1][1] = matT[1][1]; - matMT[1][2] = matT[1][2]; - matMT[2][0] = matT[2][0]; - matMT[2][1] = matT[2][1]; - matMT[2][2] = matT[2][2]; - - // calculate DResid_i/Dz_j = (delta_ij - M_i^tr * T_j) * DTrack_k/Dz_k - dr1[0] = -(matMT[0][0] * trDz.dxdz + matMT[0][1] * trDz.dydz + matMT[0][2]); - dr1[1] = -(matMT[1][0] * trDz.dxdz + matMT[1][1] * trDz.dydz + matMT[1][2]); - dr1[2] = -(matMT[2][0] * trDz.dxdz + matMT[2][1] * trDz.dydz + matMT[2][2]); - - // calculate D2Resid_I/(Dz_J Dz_K) = (delta_ijk - M_i^tr * T_j * delta_jk) * D2Track_k/dz_k^2 - dr2[0] = -(matMT[0][1] * trDz.d2ydz2 + matMT[0][0] * trDz.d2xdz2); - dr2[1] = -(matMT[1][1] * trDz.d2ydz2 + matMT[1][0] * trDz.d2xdz2); - dr2[2] = -(matMT[2][1] * trDz.d2ydz2 + matMT[2][0] * trDz.d2xdz2); - - if (i == j) { - dr1[0] += trDz.dxdz; - dr1[1] += trDz.dydz; - dr1[2] += 1.; - - dr2[0] += trDz.d2xdz2; - dr2[1] += trDz.d2ydz2; - } - } // track over which we differentiate - } // residual being differentiated -} - -//__________________________________________________________________________ -template -void FwdDCAFitterN::FwdcalcResidDerivativesNoErr() -{ - //< calculate matrix of derivatives for absolute distance chi2: residual i vs parameter Z of track j - constexpr double NInv1 = 1. - NInv; // profit from Rii = I/Ninv - for (int i = N; i--;) { // residual being differentiated - const auto& trDzi = mTrDer[mCurHyp][i]; // track point derivs over track Z param - auto& dr1ii = mDResidDz[i][i]; - auto& dr2ii = mD2ResidDz2[i][i]; - - dr1ii[0] = NInv1 * trDzi.dxdz; - dr1ii[1] = NInv1 * trDzi.dydz; - dr1ii[2] = NInv1; - - dr2ii[0] = NInv1 * trDzi.d2xdz2; - dr2ii[1] = NInv1 * trDzi.d2ydz2; - dr2ii[2] = 0; - - for (int j = i; j--;) { // track over which we differentiate - auto& dr1ij = mDResidDz[i][j]; - auto& dr1ji = mDResidDz[j][i]; - const auto& trDzj = mTrDer[mCurHyp][j]; // track point derivs over track Z param - - // calculate DResid_i/Dz_j = (delta_ij - R_ij) * DTrack_j/Dz_j for j -void FwdDCAFitterN::FwdcalcChi2Derivatives() -{ - //< calculate 1st and 2nd derivatives of wighted DCA (chi2) over track parameters Z - std::array, N> covIDrDz; // tempory vectors of covI_j * dres_j/dz_i - - // chi2 1st derivative - for (int i = N; i--;) { - auto& dchi1 = mDChi2Dz[i]; // DChi2/Dz_i = sum_j { res_j * covI_j * Dres_j/Dz_i } - dchi1 = 0; - for (int j = N; j--;) { - const auto& res = mTrRes[mCurHyp][j]; // vector of residuals of track j - const auto& covI = mTrcEInv[mCurHyp][j]; // inverse cov matrix of track j - const auto& dr1 = mDResidDz[j][i]; // vector of j-th residuals 1st derivative over Z param of track i - auto& cidr = covIDrDz[i][j]; // vector covI_j * dres_j/dz_i, save for 2nd derivative calculation - cidr[0] = covI.sxx * dr1[0] + covI.sxy * dr1[1]; - cidr[1] = covI.sxy * dr1[0] + covI.syy * dr1[1]; - cidr[2] = covI.szz * dr1[2]; - - dchi1 += ROOT::Math::Dot(res, cidr); - } - } - - // chi2 2nd derivative - for (int i = N; i--;) { - for (int j = i + 1; j--;) { // symmetric matrix - auto& dchi2 = mD2Chi2Dz2[i][j]; // D2Chi2/Dz_i/Dz_j = sum_k { Dres_k/Dz_j * covI_k * Dres_k/Dz_i + res_k * covI_k * D2res_k/Dz_i/Dz_j } - dchi2 = 0; - for (int k = N; k--;) { - const auto& dr1j = mDResidDz[k][j]; // vector of k-th residuals 1st derivative over Z param of track j - const auto& cidrkj = covIDrDz[i][k]; // vector covI_k * dres_k/dz_i - dchi2 += ROOT::Math::Dot(dr1j, cidrkj); - if (k == j) { - const auto& res = mTrRes[mCurHyp][k]; // vector of residuals of track k - const auto& covI = mTrcEInv[mCurHyp][k]; // inverse cov matrix of track k - const auto& dr2ij = mD2ResidDz2[k][j]; // vector of k-th residuals 2nd derivative over Z params of track j - dchi2 += res[0] * (covI.sxx * dr2ij[0] + covI.sxy * dr2ij[1]) + res[1] * (covI.sxy * dr2ij[0] + covI.syy * dr2ij[1]) + res[2] * covI.szz * dr2ij[2]; - } - } - } - } -} - -//__________________________________________________________________________ -template -void FwdDCAFitterN::FwdcalcChi2DerivativesNoErr() -{ - //< calculate 1st and 2nd derivatives of abs DCA (chi2) over track parameters Z - for (int i = N; i--;) { - auto& dchi1 = mDChi2Dz[i]; // DChi2/Dz_i = sum_j { res_j * Dres_j/Dz_i } - dchi1 = 0; // chi2 1st derivative - for (int j = N; j--;) { - const auto& res = mTrRes[mCurHyp][j]; // vector of residuals of track j - const auto& dr1 = mDResidDz[j][i]; // vector of j-th residuals 1st derivative over Z param of track i - dchi1 += ROOT::Math::Dot(res, dr1); - if (i >= j) { // symmetrix matrix - // chi2 2nd derivative - auto& dchi2 = mD2Chi2Dz2[i][j]; // D2Chi2/Dz_i/Dz_j = sum_k { Dres_k/Dz_j * covI_k * Dres_k/Dz_i + res_k * covI_k * D2res_k/Dz_i/Dz_j } - dchi2 = ROOT::Math::Dot(mTrRes[mCurHyp][i], mD2ResidDz2[i][j]); - for (int k = N; k--;) { - dchi2 += ROOT::Math::Dot(mDResidDz[k][i], mDResidDz[k][j]); - } - } - } - } -} - -//___________________________________________________________________ -template -void FwdDCAFitterN::FwdcalcPCA() -{ - // calculate point of closest approach for N prongs - // calculating V = sum (Ti*Pi) - mPCA[mCurHyp] = mTrCFVT[mCurHyp][N - 1] * mTrPos[mCurHyp][N - 1]; - for (int i = N - 1; i--;) { - mPCA[mCurHyp] += mTrCFVT[mCurHyp][i] * mTrPos[mCurHyp][i]; - } -} - -//___________________________________________________________________ -template -void FwdDCAFitterN::FwdcalcPCANoErr() -{ - // calculate point of closest approach for N prongs w/o errors - auto& pca = mPCA[mCurHyp]; - - pca[0] = mTrPos[mCurHyp][N - 1][0]; - pca[1] = mTrPos[mCurHyp][N - 1][1]; - pca[2] = mTrPos[mCurHyp][N - 1][2]; - - for (int i = N - 1; i--;) { - pca[0] += mTrPos[mCurHyp][i][0]; - pca[1] += mTrPos[mCurHyp][i][1]; - pca[2] += mTrPos[mCurHyp][i][2]; - } - pca[0] *= NInv; - pca[1] *= NInv; - pca[2] *= NInv; -} - -//___________________________________________________________________ -template -ROOT::Math::SMatrix> FwdDCAFitterN::calcPCACovMatrix(int cand) const -{ - // calculate covariance matrix for the point of closest approach - MatSym3D covm; - for (int i = N; i--;) { - covm += ROOT::Math::Similarity(mUseAbsDCA ? getTrackRotMatrix(i) : mTrCFVT[mOrder[cand]][i], getTrackCovMatrix(i, cand)); - } - return covm; -} - -//___________________________________________________________________ -template -void FwdDCAFitterN::FwdcalcTrackResiduals() -{ - // calculate residuals, res = Pi - V - Vec3D vtxLoc; - for (int i = N; i--;) { - mTrRes[mCurHyp][i] = mTrPos[mCurHyp][i]; - vtxLoc = mPCA[mCurHyp]; - mTrRes[mCurHyp][i] -= vtxLoc; - } -} - -//___________________________________________________________________ -template -inline void FwdDCAFitterN::calcTrackDerivatives() -{ - // calculate track derivatives over Z param - for (int i = N; i--;) { - mTrDer[mCurHyp][i].set(mCandTr[mCurHyp][i], mBz); - } -} - -//___________________________________________________________________ -template -inline double FwdDCAFitterN::FwdcalcChi2() const -{ - // calculate current chi2 - double chi2 = 0; - for (int i = N; i--;) { - const auto& res = mTrRes[mCurHyp][i]; - const auto& covI = mTrcEInv[mCurHyp][i]; - chi2 += res[0] * res[0] * covI.sxx + res[1] * res[1] * covI.syy + res[2] * res[2] * covI.szz + 2. * res[0] * res[1] * covI.sxy; - } - return chi2; -} - -//___________________________________________________________________ -template -inline double FwdDCAFitterN::FwdcalcChi2NoErr() const -{ - // calculate current chi2 of abs. distance minimization - double chi2 = 0; - for (int i = N; i--;) { - const auto& res = mTrRes[mCurHyp][i]; - chi2 += res[0] * res[0] + res[1] * res[1] + res[2] * res[2]; - } - return chi2; -} - -//___________________________________________________________________ -template -bool FwdDCAFitterN::FwdcorrectTracks(const VecND& corrZ) -{ - // propagate tracks to updated Z - for (int i = N; i--;) { - const auto& trDer = mTrDer[mCurHyp][i]; - auto dz2h = 0.5 * corrZ[i] * corrZ[i]; - mTrPos[mCurHyp][i][0] -= trDer.dxdz * corrZ[i] - dz2h * trDer.d2xdz2; - mTrPos[mCurHyp][i][1] -= trDer.dydz * corrZ[i] - dz2h * trDer.d2ydz2; - mTrPos[mCurHyp][i][2] -= corrZ[i]; - } - - return true; -} - -//___________________________________________________________________ -template -bool FwdDCAFitterN::FwdpropagateTracksToVertex(int icand) -{ - // propagate on z axis to vertex - int ord = mOrder[icand]; - if (mTrPropDone[ord]) { - return true; - } - const Vec3D& pca = mPCA[ord]; - std::array covMatrixPCA = calcPCACovMatrixFlat(ord); - std::array cov = {covMatrixPCA[0], covMatrixPCA[2]}; - for (int i = N; i--;) { - mCandTr[ord][i] = *mOrigTrPtr[i]; // fetch the track again, as mCandTr might have been propagated w/o errors - auto& trc = mCandTr[ord][i]; - const std::array p = {(float)pca[0], (float)pca[1], (float)pca[2]}; - if (!propagateToVtx(trc, p, cov)) { - return false; - } - } - - mTrPropDone[ord] = true; - return true; -} - -//___________________________________________________________________ -template -float FwdDCAFitterN::findZatXY(int mCurHyp) // Between 2 tracks -{ - - double step = 0.001; // initial step - double startPoint = 20.; // first MFT disk - - double z[2] = {startPoint, startPoint}; - double newX[2], newY[2]; - - double X = mPCA[mCurHyp][0]; // X seed - double Y = mPCA[mCurHyp][1]; // Y seed - - mCandTr[mCurHyp][0] = *mOrigTrPtr[0]; - mCandTr[mCurHyp][1] = *mOrigTrPtr[1]; - - double dstXY[2][3] = {{999., 999., 999.}, {999., 999., 999.}}; - - double Z[2]; - double finalZ[2]; - - double newDstXY; - - for (int i = 0; i < 2; i++) { - - while (z[i] > -10) { - - mCandTr[mCurHyp][i].propagateParamToZquadratic(z[i], mBz); - newX[i] = mCandTr[mCurHyp][i].getX(); - newY[i] = mCandTr[mCurHyp][i].getY(); - - newDstXY = std::sqrt((newX[i] - X) * (newX[i] - X) + - (newY[i] - Y) * (newY[i] - Y)); - - // Update points - dstXY[i][0] = dstXY[i][1]; - dstXY[i][1] = dstXY[i][2]; - dstXY[i][2] = newDstXY; - - if (dstXY[i][2] > dstXY[i][1] && dstXY[i][1] < dstXY[i][0]) { - finalZ[i] = z[i] + step; - break; - } - - z[i] -= step; - } - } - - float rez = 0.5 * (finalZ[0] + finalZ[1]); - return rez; -} - -//___________________________________________________________________ -template -void FwdDCAFitterN::findZatXY_mid(int mCurHyp) -{ - // look into dXY of T0 - T1 between 2 points(0,40cm); the one with the highest dXY is moved to mid - - double startPoint = -40.; - double endPoint = 50.; - double midPoint = 0.5 * (startPoint + endPoint); - - double z[2][2] = {{startPoint, endPoint}, {startPoint, endPoint}}; // z for tracks 0/1 on starting poing and endpoint - - double DeltaZ = std::abs(endPoint - startPoint); - - double newX[2][2]; - double newY[2][2]; - - double epsilon = 0.0001; - - double X = mPCA[mCurHyp][0]; // X seed - double Y = mPCA[mCurHyp][1]; // Y seed - - mCandTr[mCurHyp][0] = *mOrigTrPtr[0]; - mCandTr[mCurHyp][1] = *mOrigTrPtr[1]; - - double finalZ; - - double dstXY[2]; // 0 -> distance btwn both tracks at startPoint - - while (DeltaZ > epsilon) { - - midPoint = 0.5 * (startPoint + endPoint); - - for (int i = 0; i < 2; i++) { - mCandTr[mCurHyp][i].propagateParamToZquadratic(startPoint, mBz); - newX[i][0] = mCandTr[mCurHyp][i].getX(); - newY[i][0] = mCandTr[mCurHyp][i].getY(); - - mCandTr[mCurHyp][i].propagateParamToZquadratic(endPoint, mBz); - newX[i][1] = mCandTr[mCurHyp][i].getX(); - newY[i][1] = mCandTr[mCurHyp][i].getY(); - } - - dstXY[0] = (newX[0][0] - newX[1][0]) * (newX[0][0] - newX[1][0]) + - (newY[0][0] - newY[1][0]) * (newY[0][0] - newY[1][0]); - - dstXY[1] = (newX[0][1] - newX[1][1]) * (newX[0][1] - newX[1][1]) + - (newY[0][1] - newY[1][1]) * (newY[0][1] - newY[1][1]); - - DeltaZ = std::abs(endPoint - startPoint); - - if (DeltaZ < epsilon) { - finalZ = 0.5 * (startPoint + endPoint); - break; - } - - // chose new start and end Point according to the smallest D_XY - if (dstXY[1] > dstXY[0]) { - endPoint = midPoint; - } else { - startPoint = midPoint; - } - } - - mPCA[mCurHyp][2] = finalZ; -} - -//___________________________________________________________________ -template -void FwdDCAFitterN::findZatXY_lineApprox(int mCurHyp) -{ - // approx method: z=(b-b')/(a'-a) -> tracks to lines with y0,1=az0,1+b for each track (in YZ and XZ plane) - - double startPoint = 1.; - double endPoint = 50.; // first disk - - double X = mPCA[mCurHyp][0]; // X seed - double Y = mPCA[mCurHyp][1]; // Y seed - - mCandTr[mCurHyp][0] = *mOrigTrPtr[0]; - mCandTr[mCurHyp][1] = *mOrigTrPtr[1]; - - double y[2][2]; // Y00: y track 0 at point 0; Y01: y track 0 at point 1 - double z[2][2]; - double x[2][2]; - - double aYZ[2]; - double bYZ[2]; - - double aXZ[2]; - double bXZ[2]; - - double finalZ; - - // find points of the tracks = 2 straight lines - for (int i = 0; i < 2; i++) { - - mCandTr[mCurHyp][i].propagateToZquadratic(startPoint, mBz); - // mCandTr[mCurHyp][i].propagateToZlinear(startPoint); - z[i][0] = startPoint; - y[i][0] = mCandTr[mCurHyp][i].getY(); - x[i][0] = mCandTr[mCurHyp][i].getX(); - - mCandTr[mCurHyp][i].propagateToZquadratic(endPoint, mBz); - // mCandTr[mCurHyp][i].propagateToZlinear(endPoint); - z[i][1] = endPoint; - y[i][1] = mCandTr[mCurHyp][i].getY(); - x[i][1] = mCandTr[mCurHyp][i].getX(); - - bYZ[i] = (y[i][1] - y[i][0] * z[i][1] / z[i][0]) / (1 - z[i][1] / z[i][0]); - aYZ[i] = (y[i][0] - bYZ[i]) / z[i][0]; - - bXZ[i] = (x[i][1] - x[i][0] * z[i][1] / z[i][0]) / (1 - z[i][1] / z[i][0]); - aXZ[i] = (x[i][0] - bXZ[i]) / z[i][0]; - } - - // z seed: equ. for intersection of these lines - finalZ = 0.5 * ((bYZ[0] - bYZ[1]) / (aYZ[1] - aYZ[0]) + (bXZ[0] - bXZ[1]) / (aXZ[1] - aXZ[0])); - - mPCA[mCurHyp][2] = finalZ; -} - -//___________________________________________________________________ -template -void FwdDCAFitterN::findZatXY_quad(int mCurHyp) -{ - double startPoint = 0.; - double endPoint = 40.; // first disk - - double X = mPCA[mCurHyp][0]; // X seed - double Y = mPCA[mCurHyp][1]; // Y seed - - mCandTr[mCurHyp][0] = *mOrigTrPtr[0]; - mCandTr[mCurHyp][1] = *mOrigTrPtr[1]; - - double x[2]; - double y[2]; - double sinPhi0[2]; - double cosPhi0[2]; - double tanL0[2]; - double qpt0[2]; - - double k[2]; // B2C *abs(mBz) - double Hz[2]; // mBz/abs(mBz) - - double Ax[2], Bx[2], Cx[2]; - double Ay[2], By[2], Cy[2]; - - double deltaX[2], deltaY[2]; - - bool posX[2], nulX[2], negX[2]; - double z1X[2], z2X[2], z12X[2]; - - bool posY[2], nulY[2], negY[2]; - double z1Y[2], z2Y[2], z12Y[2]; - - double finalZ[2]; - - // find all variables for 2 tracks at z0 = startPoint - // set A, B, C variables for x/y equation for 2 tracks - // calculate Deltax/y for both and roots - - for (int i = 0; i < 2; i++) { - mCandTr[mCurHyp][i].propagateToZquadratic(startPoint, mBz); - x[i] = mCandTr[mCurHyp][i].getX(); - y[i] = mCandTr[mCurHyp][i].getY(); - sinPhi0[i] = mCandTr[mCurHyp][i].getSnp(); - cosPhi0[i] = std::sqrt((1. - sinPhi0[i]) * (1. + sinPhi0[i])); - tanL0[i] = mCandTr[mCurHyp][i].getTanl(); - qpt0[i] = mCandTr[mCurHyp][i].getInvQPt(); - k[i] = getK(mBz); - Hz[i] = getHz(mBz); - - Ax[i] = qpt0[i] * Hz[i] * k[i] * sinPhi0[i] / (2 * tanL0[i] * tanL0[i]); - Bx[i] = cosPhi0[i] / tanL0[i]; - Cx[i] = x[i] - X; - - Ay[i] = -qpt0[i] * Hz[i] * k[i] * cosPhi0[i] / (2 * tanL0[i] * tanL0[i]); - By[i] = sinPhi0[i] / tanL0[i]; - Cy[i] = y[i] - Y; // - - deltaX[i] = Bx[i] * Bx[i] - 4 * Ax[i] * Cx[i]; - deltaY[i] = By[i] * By[i] - 4 * Ay[i] * Cy[i]; - - if (deltaX[i] > 0) { - posX[i] = true; - z1X[i] = (-Bx[i] - std::sqrt(deltaX[i])) / (2 * Ax[i]); - z2X[i] = (-Bx[i] + std::sqrt(deltaX[i])) / (2 * Ax[i]); - } else if (deltaX[i] == 0) { - nulX[i] = true; - z12X[i] = -Bx[i] / (2 * Ax[i]); - } else { - negX[i] = true; - z12X[i] = 0; - } // discard - - if (deltaY[i] > 0) { - posY[i] = true; - z1Y[i] = (-By[i] - std::sqrt(deltaY[i])) / (2 * Ay[i]); - z2Y[i] = (-By[i] + std::sqrt(deltaY[i])) / (2 * Ay[i]); - } else if (deltaX[i] == 0) { - nulY[i] = true; - z12Y[i] = -By[i] / (2 * Ay[i]); - } else { - negY[i] = true; - z12Y[i] = 0; - } - - // find the z located in an acceptable interval - if (posX[i]) { - if (z1X[i] < endPoint && z1X[i] > startPoint) { - z12X[i] = z1X[i]; - } else { - z12X[i] = z2X[i]; - } - } - - if (posY[i]) { - if (z1Y[i] < endPoint && z1Y[i] > startPoint) { - z12Y[i] = z1Y[i]; - } else { - z12Y[i] = z2Y[i]; - } - } - - finalZ[i] = 0.5 * (z12X[i] + z12Y[i]); - } - - mPCA[mCurHyp][2] = 0.5 * (finalZ[0] + finalZ[1]); -} - -//___________________________________________________________________ -template -void FwdDCAFitterN::findZatXY_linear(int mCurHyp) -{ - - double startPoint = 0.; - - double X = mPCA[mCurHyp][0]; // X seed - double Y = mPCA[mCurHyp][1]; // Y seed - - mCandTr[mCurHyp][0] = *mOrigTrPtr[0]; - mCandTr[mCurHyp][1] = *mOrigTrPtr[1]; - - double x[2]; - double y[2]; - double sinPhi0[2]; - double cosPhi0[2]; - double tanL0[2]; - - double Ax[2], Bx[2]; - double Ay[2], By[2]; - - double z12X[2]; - double z12Y[2]; - - double finalZ[2]; - - // find all variables for 2 tracks at z0 = startPoint - // set A, B variables for x/y equation for 2 tracks - // calculate root - - for (int i = 0; i < 2; i++) { - mCandTr[mCurHyp][i].propagateToZlinear(startPoint); - x[i] = mCandTr[mCurHyp][i].getX(); - y[i] = mCandTr[mCurHyp][i].getY(); - sinPhi0[i] = mCandTr[mCurHyp][i].getSnp(); - cosPhi0[i] = std::sqrt((1. - sinPhi0[i]) * (1. + sinPhi0[i])); - tanL0[i] = mCandTr[mCurHyp][i].getTanl(); - - Ax[i] = cosPhi0[i] / tanL0[i]; - Bx[i] = x[i] - X; - - Ay[i] = sinPhi0[i] / tanL0[i]; - By[i] = y[i] - Y; - - z12X[i] = -Bx[i] / Ax[i]; - z12Y[i] = -By[i] / Ay[i]; - - finalZ[i] = 0.5 * (z12X[i] + z12Y[i]); - } - - mPCA[mCurHyp][2] = 0.5 * (finalZ[0] + finalZ[1]); -} - -//___________________________________________________________________ -template -inline o2::track::TrackParFwd FwdDCAFitterN::FwdgetTrackParamAtPCA(int i, int icand) const -{ - // propagate tracks param only to current vertex (if not already done) - int ord = mOrder[icand]; - o2::track::TrackParFwd trc(mCandTr[ord][i]); - if (!mTrPropDone[ord]) { - auto z = mPCA[ord][2]; - trc.propagateParamToZquadratic(z, mBz); - } - - return {trc}; -} - -//___________________________________________________________________ -template -inline double FwdDCAFitterN::getAbsMax(const VecND& v) -{ - double mx = -1; - for (int i = N; i--;) { - auto vai = std::abs(v[i]); - if (mx < vai) { - mx = vai; - } - } - return mx; -} - -//___________________________________________________________________ -template -bool FwdDCAFitterN::minimizeChi2() -{ - // find best chi2 (weighted DCA) of N tracks in the vicinity of the seed PCA - double x[2], y[2]; - double sumX = 0.; - double sumY = 0.; - - for (int i = N; i--;) { - mCandTr[mCurHyp][i] = *mOrigTrPtr[i]; - auto z = mPCA[mCurHyp][2]; - - mCandTr[mCurHyp][i].propagateToZquadratic(z, mBz); - - x[i] = mCandTr[mCurHyp][i].getX(); - y[i] = mCandTr[mCurHyp][i].getY(); - - setTrackPos(mTrPos[mCurHyp][i], mCandTr[mCurHyp][i]); // prepare positions - mTrcEInv[mCurHyp][i].set(mCandTr[mCurHyp][i], ZerrFactor); // prepare inverse cov.matrices at starting point - - sumX = sumX + x[i]; - sumY = sumY + y[i]; - } - - mPCA[mCurHyp][0] = sumX / N; - mPCA[mCurHyp][1] = sumY / N; - - if (mMaxDXIni > 0 && !roughDXCut()) { // apply rough cut on tracks X difference - return false; - } - - if (!FwdcalcPCACoefs()) { // prepare tracks contribution matrices to the global PCA - return false; - } - FwdcalcPCA(); // current PCA - FwdcalcTrackResiduals(); // current track residuals - float chi2Upd, chi2 = FwdcalcChi2(); - do { - calcTrackDerivatives(); // current track derivatives (1st and 2nd) - FwdcalcResidDerivatives(); // current residals derivatives (1st and 2nd) - FwdcalcChi2Derivatives(); // current chi2 derivatives (1st and 2nd) to proceed for dz calculation - - // do Newton-Rapson iteration with corrections = - dchi2/d{x0..xN} * [ d^2chi2/d{x0..xN}^2 ]^-1 - if (!mD2Chi2Dz2.Invert()) { - return false; - } - - VecND dz = mD2Chi2Dz2 * mDChi2Dz; - - if (!FwdcorrectTracks(dz)) { // calculate new Pi (mTrPos) following Newton-Rapson iteration - return false; - } - - FwdcalcPCA(); // updated mPCA (new V coordinates with new mTrPos (Pi)) - if (mCrossIDAlt >= 0 && closerToAlternative()) { - mAllowAltPreference = false; - return false; - } - - FwdcalcTrackResiduals(); // updated residuals - chi2Upd = FwdcalcChi2(); // updated chi2 - - if (getAbsMax(dz) < mMinParamChange || chi2Upd > chi2 * mMinRelChi2Change) { - chi2 = chi2Upd; - break; // converged - } - - chi2 = chi2Upd; - } while (++mNIters[mCurHyp] < mMaxIter); - - mChi2[mCurHyp] = chi2 * NInv; - return mChi2[mCurHyp] < mMaxChi2; -} - -//___________________________________________________________________ -template -bool FwdDCAFitterN::minimizeChi2NoErr() -{ - // find best chi2 (absolute DCA) of N tracks in the vicinity of the PCA seed - double x[2], y[2]; - double sumX = 0.; - double sumY = 0.; - - for (int i = N; i--;) { - - mCandTr[mCurHyp][i] = *mOrigTrPtr[i]; - - auto z = mPCA[mCurHyp][2]; - mCandTr[mCurHyp][i].propagateParamToZquadratic(z, mBz); - - x[i] = mCandTr[mCurHyp][i].getX(); - y[i] = mCandTr[mCurHyp][i].getY(); - - mPCA[mCurHyp][2] = z; - - setTrackPos(mTrPos[mCurHyp][i], mCandTr[mCurHyp][i]); // prepare positions - - sumX = sumX + x[i]; - sumY = sumY + y[i]; - } - - mPCA[mCurHyp][0] = sumX / N; - mPCA[mCurHyp][1] = sumY / N; - - if (mMaxDXIni > 0 && !roughDXCut()) { // apply rough cut on tracks Z difference - return false; - } - - FwdcalcPCANoErr(); // current PCA - FwdcalcTrackResiduals(); // current track residuals - float chi2Upd, chi2 = FwdcalcChi2NoErr(); - do { - calcTrackDerivatives(); // current track derivatives (1st and 2nd) - FwdcalcResidDerivativesNoErr(); // current residals derivatives (1st and 2nd) - FwdcalcChi2DerivativesNoErr(); // current chi2 derivatives (1st and 2nd) - - // do Newton-Rapson iteration with corrections = - dchi2/d{x0..xN} * [ d^2chi2/d{x0..xN}^2 ]^-1 - if (!mD2Chi2Dz2.Invert()) { - return false; - } - VecND dz = mD2Chi2Dz2 * mDChi2Dz; - - if (!FwdcorrectTracks(dz)) { - return false; - } - FwdcalcPCANoErr(); // updated PCA - if (mCrossIDAlt >= 0 && closerToAlternative()) { - mAllowAltPreference = false; - return false; - } - FwdcalcTrackResiduals(); // updated residuals - chi2Upd = FwdcalcChi2NoErr(); // updated chi2 - if (getAbsMax(dz) < mMinParamChange || chi2Upd > chi2 * mMinRelChi2Change) { - chi2 = chi2Upd; - break; // converged - } - chi2 = chi2Upd; - } while (++mNIters[mCurHyp] < mMaxIter); - // - mChi2[mCurHyp] = chi2 * NInv; - return mChi2[mCurHyp] < mMaxChi2; -} - -//___________________________________________________________________ -template -bool FwdDCAFitterN::roughDXCut() const -{ - // apply rough cut on DX between the tracks in the seed point - - bool accept = true; - for (int i = N; accept && i--;) { - for (int j = i; j--;) { - if (std::abs(mCandTr[mCurHyp][i].getX() - mCandTr[mCurHyp][j].getX()) > mMaxDXIni) { - accept = false; - break; - } - } - } - return accept; -} - -//___________________________________________________________________ -template -bool FwdDCAFitterN::closerToAlternative() const -{ - // check if the point current PCA point is closer to the seeding XY point being tested or to alternative see (if any) - auto dxCur = mPCA[mCurHyp][0] - mCrossings.xDCA[mCrossIDCur], dyCur = mPCA[mCurHyp][1] - mCrossings.yDCA[mCrossIDCur]; - auto dxAlt = mPCA[mCurHyp][0] - mCrossings.xDCA[mCrossIDAlt], dyAlt = mPCA[mCurHyp][1] - mCrossings.yDCA[mCrossIDAlt]; - return dxCur * dxCur + dyCur * dyCur > dxAlt * dxAlt + dyAlt * dyAlt; -} - -//___________________________________________________________________ -template -void FwdDCAFitterN::print() const -{ - LOG(info) << N << "-prong vertex fitter in " << (mUseAbsDCA ? "abs." : "weighted") << " distance minimization mode"; - LOG(info) << "Bz: " << mBz << " MaxIter: " << mMaxIter << " MaxChi2: " << mMaxChi2; - LOG(info) << "Stopping condition: Max.param change < " << mMinParamChange << " Rel.Chi2 change > " << mMinRelChi2Change; - LOG(info) << "Discard candidates for : Rvtx > " << getMaxR() << " DZ between tracks > " << mMaxDXIni; -} -//___________________________________________________________________ -template -inline bool FwdDCAFitterN::propagateToVtx(o2::track::TrackParCovFwd& t, const std::array& p, const std::array& cov) const -{ - // propagate track to vertex including MCS effects if material budget included, simple propagation to Z otherwise - float x2x0 = 0; - if (mUseMatBudget) { - auto mb = mMatLUT->getMatBudget(t.getX(), t.getY(), t.getZ(), p[0], p[1], p[2]); - x2x0 = (float)mb.meanX2X0; - return t.propagateToVtxhelixWithMCS(p[2], {p[0], p[1]}, cov, mBz, x2x0); - } else if (mTGeoFallBackAllowed) { - auto geoMan = o2::base::GeometryManager::meanMaterialBudget(t.getX(), t.getY(), t.getZ(), p[0], p[1], p[2]); - x2x0 = (float)geoMan.meanX2X0; - return t.propagateToVtxhelixWithMCS(p[2], {p[0], p[1]}, cov, mBz, x2x0); - } else { - t.propagateToZhelix(p[2], mBz); - return true; - } -} - -using FwdDCAFitter2 = FwdDCAFitterN<2, o2::track::TrackParCovFwd>; -using FwdDCAFitter3 = FwdDCAFitterN<3, o2::track::TrackParCovFwd>; - -} // namespace vertexing -} // namespace o2 -#endif // _ALICEO2_DCA_FWDFITTERN_ diff --git a/Detectors/Vertexing/src/FwdDCAFitterN.cxx b/Detectors/Vertexing/src/FwdDCAFitterN.cxx deleted file mode 100644 index f7176aa5039fd..0000000000000 --- a/Detectors/Vertexing/src/FwdDCAFitterN.cxx +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file DCAFitterN.cxx -/// \brief Defintions for N-prongs secondary vertex fit -/// \author ruben.shahoyan@cern.ch, adapted from central barrel to fwd rapidities by Rita Sadek, rita.sadek@cern.ch - -#include "DetectorsVertexing/FwdDCAFitterN.h" - -namespace o2 -{ -namespace vertexing -{ - -void __test_instance__() -{ - FwdDCAFitter2 ft2; - FwdDCAFitter3 ft3; - o2::track::TrackParCovFwd tr; - ft2.process(tr, tr); - ft3.process(tr, tr, tr); -} - -} // namespace vertexing -} // namespace o2 From 35c99fbf9c4a2c42e6cc220c119441ad22dfd059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ku=C4=8Dera?= <26327373+vkucera@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:05:45 +0100 Subject: [PATCH 187/234] ITSMFT: Delete unused files (#15034) --- .../MFTCalibration/NoiseSlotCalibrator.h | 101 - .../MFT/calibration/src/MchAlignment.cxx | 1660 ----------------- .../calibration/src/NoiseSlotCalibrator.cxx | 145 -- 3 files changed, 1906 deletions(-) delete mode 100644 Detectors/ITSMFT/MFT/calibration/include/MFTCalibration/NoiseSlotCalibrator.h delete mode 100644 Detectors/ITSMFT/MFT/calibration/src/MchAlignment.cxx delete mode 100644 Detectors/ITSMFT/MFT/calibration/src/NoiseSlotCalibrator.cxx diff --git a/Detectors/ITSMFT/MFT/calibration/include/MFTCalibration/NoiseSlotCalibrator.h b/Detectors/ITSMFT/MFT/calibration/include/MFTCalibration/NoiseSlotCalibrator.h deleted file mode 100644 index a8280467b14c9..0000000000000 --- a/Detectors/ITSMFT/MFT/calibration/include/MFTCalibration/NoiseSlotCalibrator.h +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file NoiseSlotCalibrator.h - -#ifndef O2_MFT_NOISESLOTCALIBRATOR -#define O2_MFT_NOISESLOTCALIBRATOR - -#include - -#include "DetectorsCalibration/TimeSlotCalibration.h" -#include "DetectorsCalibration/TimeSlot.h" - -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/Digit.h" -#include "DataFormatsITSMFT/NoiseMap.h" -#include "gsl/span" - -namespace o2 -{ - -namespace itsmft -{ -class ROFRecord; -} // namespace itsmft - -namespace mft -{ - -class NoiseSlotCalibrator : public o2::calibration::TimeSlotCalibration -{ - using Slot = calibration::TimeSlot; - - public: - NoiseSlotCalibrator() { setUpdateAtTheEndOfRunOnly(); } - NoiseSlotCalibrator(float prob, float relErr) : mProbabilityThreshold(prob), mProbRelErr(relErr) - { - setUpdateAtTheEndOfRunOnly(); - setSlotLength(INFINITE_TF); - mMinROFs = 1.1 * o2::itsmft::NoiseMap::getMinROFs(prob, relErr); - LOGP(info, "At least {} ROFs needed to apply threshold {} with relative error {}", mMinROFs, mProbabilityThreshold, mProbRelErr); - } - ~NoiseSlotCalibrator() final = default; - - void setThreshold(unsigned int t) { mThreshold = t; } - - bool processTimeFrame(calibration::TFType tf, - gsl::span const& digits, - gsl::span const& rofs); - - bool processTimeFrame(calibration::TFType tf, - gsl::span const& clusters, - gsl::span const& patterns, - gsl::span const& rofs); - - void setMinROFs(long n) { mMinROFs = n; } - - void finalize() - { - LOG(info) << "Number of processed strobes is " << mNumberOfStrobes; - auto& slot = getSlots().back(); - slot.getContainer()->applyProbThreshold(mProbabilityThreshold, mNumberOfStrobes); - } - - const o2::itsmft::NoiseMap& getNoiseMap(long& start, long& end) - { - const auto& slot = getSlots().back(); - start = slot.getTFStart(); - end = slot.getTFEnd(); - return *(slot.getContainer()); - } - - // Functions overloaded from the calibration framework - bool process(calibration::TFType tf, const gsl::span data) final; - - // Functions required by the calibration framework - void initOutput() final {} - Slot& emplaceNewSlot(bool, calibration::TFType, calibration::TFType) final; - void finalizeSlot(Slot& slot) final; - bool hasEnoughData(const Slot& slot) const final; - - private: - float mProbabilityThreshold = 1e-6f; - float mProbRelErr = 0.2; // relative error on channel noise to apply the threshold - long mMinROFs = 0; - unsigned int mThreshold = 100; - unsigned int mNumberOfStrobes = 0; -}; - -} // namespace mft -} // namespace o2 - -#endif /* O2_MFT_NOISESLOTCALIBRATOR */ diff --git a/Detectors/ITSMFT/MFT/calibration/src/MchAlignment.cxx b/Detectors/ITSMFT/MFT/calibration/src/MchAlignment.cxx deleted file mode 100644 index b9e590cca0b63..0000000000000 --- a/Detectors/ITSMFT/MFT/calibration/src/MchAlignment.cxx +++ /dev/null @@ -1,1660 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -//----------------------------------------------------------------------------- -/// \file Alignment -/// Alignment class for the ALICE DiMuon spectrometer -/// -/// MUON specific alignment class which interface to AliMillepede. -/// For each track ProcessTrack calculates the local and global derivatives -/// at each cluster and fill the corresponding local equations. Provide methods -/// for fixing or constraining detection elements for best results. -/// -/// \author Javier Castillo Castellanos -//----------------------------------------------------------------------------- - -#include "MCHAlign/Alignment.h" -#include "MCHAlign/MillePede2.h" -#include "MCHAlign/MillePedeRecord.h" -#include - -#include "MCHTracking/Track.h" -#include "MCHTracking/TrackParam.h" -#include "MCHTracking/Cluster.h" -#include "TGeoManager.h" - -// #include "DataFormatsMCH/ROFRecord.h" -// #include "DataFormatsMCH/TrackMCH.h" -// #include "DataFormatsMCH/Cluster.h" -// #include "DataFormatsMCH/Digit.h" - -// #include "AliMUONGeometryTransformer.h" -// #include "AliMUONGeometryModuleTransformer.h" -// #include "MCHAlign/AliMUONGeometryDetElement.h" -// #include "AliMUONGeometryBuilder.h" -#include "MCHGeometryCreator/Geometry.h" -#include "MCHGeometryTest/Helpers.h" -#include "MCHGeometryTransformer/Transformations.h" -#include "TGeoManager.h" - -// #include "Align/Millepede2Record.h" //to be replaced -// #include "AliMpExMap.h" -// #include "AliMpExMapIterator.h" - -#include "DetectorsCommonDataFormats/AlignParam.h" -#include "Framework/Logger.h" - -#include -#include -#include -#include -#include -#include - -namespace o2 -{ -namespace mch -{ - -using namespace std; - -//_____________________________________________________________________ -// static variables -const Int_t Alignment::fgNDetElemCh[Alignment::fgNCh] = {4, 4, 4, 4, 18, 18, 26, 26, 26, 26}; -const Int_t Alignment::fgSNDetElemCh[Alignment::fgNCh + 1] = {0, 4, 8, 12, 16, 34, 52, 78, 104, 130, 156}; - -// number of detector elements in each half-chamber -const Int_t Alignment::fgNDetElemHalfCh[Alignment::fgNHalfCh] = {2, 2, 2, 2, 2, 2, 2, 2, 9, 9, 9, 9, 13, 13, 13, 13, 13, 13, 13, 13}; - -// list of detector elements for each half chamber -const Int_t Alignment::fgDetElemHalfCh[Alignment::fgNHalfCh][Alignment::fgNDetHalfChMax] = - { - {100, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {101, 102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - - {200, 203, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {201, 202, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - - {300, 303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {301, 302, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - - {400, 403, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {401, 402, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - - {500, 501, 502, 503, 504, 514, 515, 516, 517, 0, 0, 0, 0}, - {505, 506, 507, 508, 509, 510, 511, 512, 513, 0, 0, 0, 0}, - - {600, 601, 602, 603, 604, 614, 615, 616, 617, 0, 0, 0, 0}, - {605, 606, 607, 608, 609, 610, 611, 612, 613, 0, 0, 0, 0}, - - {700, 701, 702, 703, 704, 705, 706, 720, 721, 722, 723, 724, 725}, - {707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719}, - - {800, 801, 802, 803, 804, 805, 806, 820, 821, 822, 823, 824, 825}, - {807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819}, - - {900, 901, 902, 903, 904, 905, 906, 920, 921, 922, 923, 924, 925}, - {907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919}, - - {1000, 1001, 1002, 1003, 1004, 1005, 1006, 1020, 1021, 1022, 1023, 1024, 1025}, - {1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019} - -}; - -//_____________________________________________________________________ -/// self initialized array, used for adding constraints -class Array -{ - - public: - /// contructor - Array(void) - { - for (Int_t i = 0; i < Alignment::fNGlobal; ++i) { - values[i] = 0; - } - } - - /// array - Double_t values[Alignment::fNGlobal]; - - private: - /// Not implemented - Array(const Array&); - - /// Not implemented - Array& operator=(const Array&); -}; - -//________________________________________________________________________ -Double_t Square(Double_t x) { return x * x; } - -//_____________________________________________________________________ -Alignment::Alignment() - : TObject(), - fInitialized(kFALSE), - fRunNumber(0), - fBFieldOn(kFALSE), - fRefitStraightTracks(kFALSE), - fStartFac(256), - fResCutInitial(100), - fResCut(100), - fMillepede(0L), // to be modified - fCluster(0L), - fNStdDev(3), - fDetElemNumber(0), - fTrackRecord(), - fTransformCreator(), - fGeoCombiTransInverse(), - fDoEvaluation(kFALSE), - fTrackParamOrig(0), - fTrackParamNew(0), - fTFile(0), - fTTree(0) -{ - /// constructor - fSigma[0] = 1.5e-1; - fSigma[1] = 1.0e-2; - - // default allowed variations - fAllowVar[0] = 0.5; // x - fAllowVar[1] = 0.5; // y - fAllowVar[2] = 0.01; // phi_z - fAllowVar[3] = 5; // z - - // initialize millepede - fMillepede = new MillePede2(); - // fMillepede = new o2::align::Mille("theMilleFile.txt"); // To be replaced by MillePede2 - - // initialize degrees of freedom - // by default all parameters are free - for (Int_t iPar = 0; iPar < fNGlobal; ++iPar) { - fGlobalParameterStatus[iPar] = kFreeParId; - } - - // initialize local equations - for (int i = 0; i < fNLocal; ++i) { - fLocalDerivatives[i] = 0.0; - } - - for (int i = 0; i < fNGlobal; ++i) { - fGlobalDerivatives[i] = 0.0; - } -} - -//_____________________________________________________________________ -// Alignment::~Alignment() -//{ -// /// destructor -//} -// Alignment::~Alignment() = default; -//_____________________________________________________________________ -void Alignment::init(void) -{ - - /// initialize - /** - initialize millipede - must be called after necessary detectors have been fixed, - but before constrains are added and before global parameters initial value are set - */ - if (fInitialized) { - LOG(fatal) << "Millepede already initialized"; - } - - // assign proper groupID to free parameters - Int_t nGlobal = 0; - for (Int_t iPar = 0; iPar < fNGlobal; ++iPar) { - - if (fGlobalParameterStatus[iPar] == kFixedParId) { - // fixed parameters are left unchanged - continue; - - } else if (fGlobalParameterStatus[iPar] == kFreeParId || fGlobalParameterStatus[iPar] == kGroupBaseId) { - - // free parameters or first element of group are assigned a new group id - fGlobalParameterStatus[iPar] = nGlobal++; - continue; - - } else if (fGlobalParameterStatus[iPar] < kGroupBaseId) { - - // get detector element id from status, get chamber parameter id - const Int_t iDeBase(kGroupBaseId - 1 - fGlobalParameterStatus[iPar]); - const Int_t iParBase = iPar % fgNParCh; - - // check - if (iDeBase < 0 || iDeBase >= iPar / fgNParCh) { - LOG(fatal) << "Group for parameter index " << iPar << " has wrong base detector element: " << iDeBase; - } - - // assign identical group id to current - fGlobalParameterStatus[iPar] = fGlobalParameterStatus[iDeBase * fgNParCh + iParBase]; - LOG(info) << "Parameter " << iPar << " grouped to detector " << iDeBase << " (" << GetParameterMaskString(1 << iParBase).Data() << ")"; - - } else - LOG(fatal) << "Unrecognized parameter status for index " << iPar << ": " << fGlobalParameterStatus[iPar]; - } - - LOG(info) << "Free Parameters: " << nGlobal << " out of " << fNGlobal; - - // initialize millepede - // fMillepede->InitMille(fNGlobal, fNLocal, fNStdDev, fResCut, fResCutInitial, fGlobalParameterStatus); - fMillepede->InitMille(fNGlobal, fNLocal, fNStdDev, fResCut, fResCutInitial); // MillePede2 implementation - - fInitialized = kTRUE; - - // some debug output - for (Int_t iPar = 0; iPar < fgNParCh; ++iPar) { - LOG(info) << "fAllowVar[" << iPar << "]= " << fAllowVar[iPar]; - } - - // set allowed variations for all parameters - for (Int_t iDet = 0; iDet < fgNDetElem; ++iDet) { - for (Int_t iPar = 0; iPar < fgNParCh; ++iPar) { - fMillepede->SetParSigma(iDet * fgNParCh + iPar, fAllowVar[iPar]); - } - } - - // Set iterations - if (fStartFac > 1) { - fMillepede->SetIterations(fStartFac); - } - // setup monitoring TFile - if (fDoEvaluation && fRefitStraightTracks) { - fTFile = new TFile("Alignment.root", "RECREATE"); - fTTree = new TTree("TreeE", "Evaluation"); - - const Int_t kSplitlevel = 98; - const Int_t kBufsize = 32000; - - fTrackParamOrig = new LocalTrackParam(); - fTTree->Branch("fTrackParamOrig", "LocalTrackParam", &fTrackParamOrig, kBufsize, kSplitlevel); - - fTrackParamNew = new LocalTrackParam(); - fTTree->Branch("fTrackParamNew", "LocalTrackParam", &fTrackParamNew, kBufsize, kSplitlevel); - } -} - -//_____________________________________________________ -void Alignment::terminate(void) -{ - LOG(info) << "Closing Evaluation TFile"; - if (fTFile && fTTree) { - fTFile->cd(); - fTTree->Write(); - fTFile->Close(); - } -} - -//_____________________________________________________ -MillePedeRecord* Alignment::ProcessTrack(Track& track, Bool_t doAlignment, Double_t weight) -{ - /// process track for alignment minimization - /** - returns the alignment records for this track. - They can be stored in some output for later reprocessing. - */ - - // reset track records - fTrackRecord.Reset(); - if (fMillepede->GetRecord()) { - fMillepede->GetRecord()->Reset(); - } - - // loop over clusters to get starting values - Bool_t first(kTRUE); - // if (!trackParam) - // continue; - for (auto itTrackParam(track.begin()); itTrackParam != track.end(); ++itTrackParam) { - - // get cluster - const Cluster* Cluster = itTrackParam->getClusterPtr(); - if (!cluster) - continue; - - // for first valid cluster, save track position as "starting" values - if (first) { - - first = kFALSE; - FillTrackParamData(&*itTrackParam); - fTrackPos0[0] = fTrackPos[0]; - fTrackPos0[1] = fTrackPos[1]; - fTrackPos0[2] = fTrackPos[2]; - fTrackSlope0[0] = fTrackSlope[0]; - fTrackSlope0[1] = fTrackSlope[1]; - - break; - } - } - - // redo straight track fit - if (fRefitStraightTracks) { - - // refit straight track - const LocalTrackParam trackParam(RefitStraightTrack(track, fTrackPos0[2])); - - // fill evaluation tree - if (fTrackParamOrig) { - fTrackParamOrig->fTrackX = fTrackPos0[0]; - fTrackParamOrig->fTrackY = fTrackPos0[1]; - fTrackParamOrig->fTrackZ = fTrackPos0[2]; - fTrackParamOrig->fTrackSlopeX = fTrackSlope[0]; - fTrackParamOrig->fTrackSlopeY = fTrackSlope[1]; - } - - // new ones - if (fTrackParamNew) { - fTrackParamNew->fTrackX = trackParam.fTrackX; - fTrackParamNew->fTrackY = trackParam.fTrackY; - fTrackParamNew->fTrackZ = trackParam.fTrackZ; - fTrackParamNew->fTrackSlopeX = trackParam.fTrackSlopeX; - fTrackParamNew->fTrackSlopeY = trackParam.fTrackSlopeY; - } - - if (fTTree) - fTTree->Fill(); - - /* - copy new parameters to stored ones for derivatives calculation - this is done only if BFieldOn is false, for which these parameters are used - */ - if (!fBFieldOn) { - fTrackPos0[0] = trackParam.fTrackX; - fTrackPos0[1] = trackParam.fTrackY; - fTrackPos0[2] = trackParam.fTrackZ; - fTrackSlope[0] = trackParam.fTrackSlopeX; - fTrackSlope[1] = trackParam.fTrackSlopeY; - } - } - - // second loop to perform alignment - for (auto itTrackParam(track.begin()); itTrackParam != track.end(); ++itTrackParam) { - - // get track parameters - if (!&*itTrackParam) - continue; - - // get cluster - const Cluster* cluster = itTrackParam->getClusterPtr(); - if (!cluster) - continue; - - // fill local variables for this position --> one measurement - FillDetElemData(cluster); - FillRecPointData(cluster); - FillTrackParamData(&*itTrackParam); - - // 'inverse' (GlobalToLocal) rotation matrix - const Double_t* r(fGeoCombiTransInverse.GetRotationMatrix()); - - // calculate measurements - if (fBFieldOn) { - - // use residuals (cluster - track) for measurement - fMeas[0] = r[0] * (fClustPos[0] - fTrackPos[0]) + r[1] * (fClustPos[1] - fTrackPos[1]); - fMeas[1] = r[3] * (fClustPos[0] - fTrackPos[0]) + r[4] * (fClustPos[1] - fTrackPos[1]); - - } else { - - // use cluster position for measurement - fMeas[0] = (r[0] * fClustPos[0] + r[1] * fClustPos[1]); - fMeas[1] = (r[3] * fClustPos[0] + r[4] * fClustPos[1]); - } - - // Set local equations - LocalEquationX(); - LocalEquationY(); - } - - // copy track record - fMillepede->SetRecordRun(fRunNumber); - fMillepede->SetRecordWeight(weight); - fTrackRecord = *fMillepede->GetRecord(); - - // save record data - if (doAlignment) { - fMillepede->SaveRecordData(); - fMillepede->CloseDataRecStorage(); - } - - // return record - return &fTrackRecord; -} - -//______________________________________________________________________________ -void Alignment::ProcessTrack(MillePedeRecord* trackRecord) -{ - LOG(fatal) << __PRETTY_FUNCTION__ << " is disabled"; - - /// process track record - if (!trackRecord) - return; - - // // make sure record storage is initialized - if (!fMillepede->GetRecord()) { - fMillepede->InitDataRecStorage(kFalse); - } - // // copy content - *fMillepede->GetRecord() = *trackRecord; - - // save record - fMillepede->SaveRecordData(); - // write to local file - fMillepede->CloseDataRecStorage(); - - return; -} - -//_____________________________________________________________________ -void Alignment::FixAll(UInt_t mask) -{ - /// fix parameters matching mask, for all chambers - LOG(info) << "Fixing " << GetParameterMaskString(mask).Data() << " for all detector elements"; - - // fix all stations - for (Int_t i = 0; i < fgNDetElem; ++i) { - if (mask & ParX) - FixParameter(i, 0); - if (mask & ParY) - FixParameter(i, 1); - if (mask & ParTZ) - FixParameter(i, 2); - if (mask & ParZ) - FixParameter(i, 3); - } -} - -//_____________________________________________________________________ -void Alignment::FixChamber(Int_t iCh, UInt_t mask) -{ - /// fix parameters matching mask, for all detector elements in a given chamber, counting from 1 - - // check boundaries - if (iCh < 1 || iCh > 10) { - LOG(fatal) << "Invalid chamber index " << iCh; - } - - // get first and last element - const Int_t iDetElemFirst = fgSNDetElemCh[iCh - 1]; - const Int_t iDetElemLast = fgSNDetElemCh[iCh]; - for (Int_t i = iDetElemFirst; i < iDetElemLast; ++i) { - - LOG(info) << "Fixing " << GetParameterMaskString(mask).Data() << " for detector element " << i; - - if (mask & ParX) - FixParameter(i, 0); - if (mask & ParY) - FixParameter(i, 1); - if (mask & ParTZ) - FixParameter(i, 2); - if (mask & ParZ) - FixParameter(i, 3); - } -} - -//_____________________________________________________________________ -void Alignment::FixDetElem(Int_t iDetElemId, UInt_t mask) -{ - /// fix parameters matching mask, for a given detector element, counting from 0 - const Int_t iDet(GetDetElemNumber(iDetElemId)); - if (mask & ParX) - FixParameter(iDet, 0); - if (mask & ParY) - FixParameter(iDet, 1); - if (mask & ParTZ) - FixParameter(iDet, 2); - if (mask & ParZ) - FixParameter(iDet, 3); -} - -//_____________________________________________________________________ -void Alignment::FixHalfSpectrometer(const Bool_t* lChOnOff, UInt_t sidesMask, UInt_t mask) -{ - - /// Fix parameters matching mask for all detectors in selected chambers and selected sides of the spectrometer - for (Int_t i = 0; i < fgNDetElem; ++i) { - - // get chamber matching detector - const Int_t iCh(GetChamberId(i)); - if (!lChOnOff[iCh - 1]) - continue; - - // get detector element in chamber - Int_t lDetElemNumber = i - fgSNDetElemCh[iCh - 1]; - - // skip detector if its side is off - // stations 1 and 2 - if (iCh >= 1 && iCh <= 4) { - if (lDetElemNumber == 0 && !(sidesMask & SideTopRight)) - continue; - if (lDetElemNumber == 1 && !(sidesMask & SideTopLeft)) - continue; - if (lDetElemNumber == 2 && !(sidesMask & SideBottomLeft)) - continue; - if (lDetElemNumber == 3 && !(sidesMask & SideBottomRight)) - continue; - } - - // station 3 - if (iCh >= 5 && iCh <= 6) { - if (lDetElemNumber >= 0 && lDetElemNumber <= 4 && !(sidesMask & SideTopRight)) - continue; - if (lDetElemNumber >= 5 && lDetElemNumber <= 10 && !(sidesMask & SideTopLeft)) - continue; - if (lDetElemNumber >= 11 && lDetElemNumber <= 13 && !(sidesMask & SideBottomLeft)) - continue; - if (lDetElemNumber >= 14 && lDetElemNumber <= 17 && !(sidesMask & SideBottomRight)) - continue; - } - - // stations 4 and 5 - if (iCh >= 7 && iCh <= 10) { - if (lDetElemNumber >= 0 && lDetElemNumber <= 6 && !(sidesMask & SideTopRight)) - continue; - if (lDetElemNumber >= 7 && lDetElemNumber <= 13 && !(sidesMask & SideTopLeft)) - continue; - if (lDetElemNumber >= 14 && lDetElemNumber <= 19 && !(sidesMask & SideBottomLeft)) - continue; - if (lDetElemNumber >= 20 && lDetElemNumber <= 25 && !(sidesMask & SideBottomRight)) - continue; - } - - // detector is accepted, fix it - FixDetElem(i, mask); - } -} - -//______________________________________________________________________ -void Alignment::FixParameter(Int_t iPar) -{ - - /// fix a given parameter, counting from 0 - if (fInitialized) { - LOG(fatal) << "Millepede already initialized"; - } - - fGlobalParameterStatus[iPar] = kFixedParId; -} - -//_____________________________________________________________________ -void Alignment::ReleaseChamber(Int_t iCh, UInt_t mask) -{ - /// release parameters matching mask, for all detector elements in a given chamber, counting from 1 - - // check boundaries - if (iCh < 1 || iCh > 10) { - LOG(fatal) << "Invalid chamber index " << iCh; - } - - // get first and last element - const Int_t iDetElemFirst = fgSNDetElemCh[iCh - 1]; - const Int_t iDetElemLast = fgSNDetElemCh[iCh]; - for (Int_t i = iDetElemFirst; i < iDetElemLast; ++i) { - - LOG(info) << "Releasing " << GetParameterMaskString(mask).Data() << " for detector element " << i; - - if (mask & ParX) - ReleaseParameter(i, 0); - if (mask & ParY) - ReleaseParameter(i, 1); - if (mask & ParTZ) - ReleaseParameter(i, 2); - if (mask & ParZ) - ReleaseParameter(i, 3); - } -} - -//_____________________________________________________________________ -void Alignment::ReleaseDetElem(Int_t iDetElemId, UInt_t mask) -{ - /// release parameters matching mask, for a given detector element, counting from 0 - const Int_t iDet(GetDetElemNumber(iDetElemId)); - if (mask & ParX) - ReleaseParameter(iDet, 0); - if (mask & ParY) - ReleaseParameter(iDet, 1); - if (mask & ParTZ) - ReleaseParameter(iDet, 2); - if (mask & ParZ) - ReleaseParameter(iDet, 3); -} - -//______________________________________________________________________ -void Alignment::ReleaseParameter(Int_t iPar) -{ - - /// release a given parameter, counting from 0 - if (fInitialized) { - LOG(fatal) << "Millepede already initialized"; - } - - fGlobalParameterStatus[iPar] = kFreeParId; -} - -//_____________________________________________________________________ -void Alignment::GroupChamber(Int_t iCh, UInt_t mask) -{ - /// group parameters matching mask for all detector elements in a given chamber, counting from 1 - if (iCh < 1 || iCh > fgNCh) { - LOG(fatal) << "Invalid chamber index " << iCh; - } - - const Int_t detElemMin = 100 * iCh; - const Int_t detElemMax = 100 * iCh + fgNDetElemCh[iCh] - 1; - GroupDetElems(detElemMin, detElemMax, mask); -} - -//_____________________________________________________________________ -void Alignment::GroupHalfChamber(Int_t iCh, Int_t iHalf, UInt_t mask) -{ - /// group parameters matching mask for all detector elements in a given tracking module (= half chamber), counting from 0 - if (iCh < 1 || iCh > fgNCh) { - LOG(fatal) << "Invalid chamber index " << iCh; - } - - if (iHalf < 0 || iHalf > 1) { - LOG(fatal) << "Invalid half chamber index " << iHalf; - } - - const Int_t iHalfCh = 2 * (iCh - 1) + iHalf; - GroupDetElems(&fgDetElemHalfCh[iHalfCh][0], fgNDetElemHalfCh[iHalfCh], mask); -} - -//_____________________________________________________________________ -void Alignment::GroupDetElems(Int_t detElemMin, Int_t detElemMax, UInt_t mask) -{ - /// group parameters matching mask for all detector elements between min and max - // check number of detector elements - const Int_t nDetElem = detElemMax - detElemMin + 1; - if (nDetElem < 2) { - LOG(fatal) << "Requested group of DEs " << detElemMin << "-" << detElemMax << " contains less than 2 DE's"; - } - - // create list - Int_t* detElemList = new int[nDetElem]; - for (Int_t i = 0; i < nDetElem; ++i) { - detElemList[i] = detElemMin + i; - } - - // group - GroupDetElems(detElemList, nDetElem, mask); - delete[] detElemList; -} - -//_____________________________________________________________________ -void Alignment::GroupDetElems(const Int_t* detElemList, Int_t nDetElem, UInt_t mask) -{ - /// group parameters matching mask for all detector elements in list - if (fInitialized) { - LOG(fatal) << "Millepede already initialized"; - } - - const Int_t iDeBase(GetDetElemNumber(detElemList[0])); - for (Int_t i = 0; i < nDetElem; ++i) { - const Int_t iDeCurrent(GetDetElemNumber(detElemList[i])); - if (mask & ParX) - fGlobalParameterStatus[iDeCurrent * fgNParCh + 0] = (i == 0) ? kGroupBaseId : (kGroupBaseId - iDeBase - 1); - if (mask & ParY) - fGlobalParameterStatus[iDeCurrent * fgNParCh + 1] = (i == 0) ? kGroupBaseId : (kGroupBaseId - iDeBase - 1); - if (mask & ParTZ) - fGlobalParameterStatus[iDeCurrent * fgNParCh + 2] = (i == 0) ? kGroupBaseId : (kGroupBaseId - iDeBase - 1); - if (mask & ParZ) - fGlobalParameterStatus[iDeCurrent * fgNParCh + 3] = (i == 0) ? kGroupBaseId : (kGroupBaseId - iDeBase - 1); - - if (i == 0) - LOG(info) << "Creating new group for detector " << detElemList[i] << " and variable " << GetParameterMaskString(mask).Data(); - else - LOG(info) << "Adding detector element " << detElemList[i] << " to current group"; - } -} - -//______________________________________________________________________ -void Alignment::SetChamberNonLinear(Int_t iCh, UInt_t mask) -{ - /// Set parameters matching mask as non linear, for all detector elements in a given chamber, counting from 1 - const Int_t iDetElemFirst = fgSNDetElemCh[iCh - 1]; - const Int_t iDetElemLast = fgSNDetElemCh[iCh]; - for (Int_t i = iDetElemFirst; i < iDetElemLast; ++i) { - - if (mask & ParX) - SetParameterNonLinear(i, 0); - if (mask & ParY) - SetParameterNonLinear(i, 1); - if (mask & ParTZ) - SetParameterNonLinear(i, 2); - if (mask & ParZ) - SetParameterNonLinear(i, 3); - } -} - -//_____________________________________________________________________ -void Alignment::SetDetElemNonLinear(Int_t iDetElemId, UInt_t mask) -{ - /// Set parameters matching mask as non linear, for a given detector element, counting from 0 - const Int_t iDet(GetDetElemNumber(iDetElemId)); - if (mask & ParX) - SetParameterNonLinear(iDet, 0); - if (mask & ParY) - SetParameterNonLinear(iDet, 1); - if (mask & ParTZ) - SetParameterNonLinear(iDet, 2); - if (mask & ParZ) - SetParameterNonLinear(iDet, 3); -} - -//______________________________________________________________________ -void Alignment::SetParameterNonLinear(Int_t iPar) -{ - /// Set nonlinear flag for parameter iPar - if (!fInitialized) { - LOG(fatal) << "Millepede not initialized"; - } - - fMillepede->SetNonLinear(iPar); - LOG(info) << "Parameter " << iPar << " set to non linear "; -} - -//______________________________________________________________________ -void Alignment::AddConstraints(const Bool_t* lChOnOff, UInt_t mask) -{ - /// Add constraint equations for selected chambers and degrees of freedom - - Array fConstraintX; - Array fConstraintY; - Array fConstraintTZ; - Array fConstraintZ; - - for (Int_t i = 0; i < fgNDetElem; ++i) { - - // get chamber matching detector - const Int_t iCh(GetChamberId(i)); - if (lChOnOff[iCh - 1]) { - - if (mask & ParX) - fConstraintX.values[i * fgNParCh + 0] = 1.0; - if (mask & ParY) - fConstraintY.values[i * fgNParCh + 1] = 1.0; - if (mask & ParTZ) - fConstraintTZ.values[i * fgNParCh + 2] = 1.0; - if (mask & ParZ) - fConstraintTZ.values[i * fgNParCh + 3] = 1.0; - } - } - - if (mask & ParX) - AddConstraint(fConstraintX.values, 0.0); - if (mask & ParY) - AddConstraint(fConstraintY.values, 0.0); - if (mask & ParTZ) - AddConstraint(fConstraintTZ.values, 0.0); - if (mask & ParZ) - AddConstraint(fConstraintZ.values, 0.0); -} - -//______________________________________________________________________ -void Alignment::AddConstraints(const Bool_t* lChOnOff, const Bool_t* lVarXYT, UInt_t sidesMask) -{ - /* - questions: - - is there not redundancy/inconsistency between lDetTLBR and lSpecLROnOff ? shouldn't we use only lDetTLBR ? - - why is weight ignored for ConstrainT and ConstrainB - - why is there no constrain on z - */ - - /// Add constraint equations for selected chambers, degrees of freedom and detector half - Double_t lMeanY = 0.; - Double_t lSigmaY = 0.; - Double_t lMeanZ = 0.; - Double_t lSigmaZ = 0.; - Int_t lNDetElem = 0; - - for (Int_t i = 0; i < fgNDetElem; ++i) { - - // get chamber matching detector - const Int_t iCh(GetChamberId(i)); - - // skip detector if chamber is off - if (lChOnOff[iCh - 1]) - continue; - - // get detector element id from detector element number - const Int_t lDetElemNumber = i - fgSNDetElemCh[iCh - 1]; - const Int_t lDetElemId = iCh * 100 + lDetElemNumber; - - // skip detector if its side is off - // stations 1 and 2 - if (iCh >= 1 && iCh <= 4) { - if (lDetElemNumber == 0 && !(sidesMask & SideTopRight)) - continue; - if (lDetElemNumber == 1 && !(sidesMask & SideTopLeft)) - continue; - if (lDetElemNumber == 2 && !(sidesMask & SideBottomLeft)) - continue; - if (lDetElemNumber == 3 && !(sidesMask & SideBottomRight)) - continue; - } - - // station 3 - if (iCh >= 5 && iCh <= 6) { - if (lDetElemNumber >= 0 && lDetElemNumber <= 4 && !(sidesMask & SideTopRight)) - continue; - if (lDetElemNumber >= 5 && lDetElemNumber <= 10 && !(sidesMask & SideTopLeft)) - continue; - if (lDetElemNumber >= 11 && lDetElemNumber <= 13 && !(sidesMask & SideBottomLeft)) - continue; - if (lDetElemNumber >= 14 && lDetElemNumber <= 17 && !(sidesMask & SideBottomRight)) - continue; - } - - // stations 4 and 5 - if (iCh >= 7 && iCh <= 10) { - if (lDetElemNumber >= 0 && lDetElemNumber <= 6 && !(sidesMask & SideTopRight)) - continue; - if (lDetElemNumber >= 7 && lDetElemNumber <= 13 && !(sidesMask & SideTopLeft)) - continue; - if (lDetElemNumber >= 14 && lDetElemNumber <= 19 && !(sidesMask & SideBottomLeft)) - continue; - if (lDetElemNumber >= 20 && lDetElemNumber <= 25 && !(sidesMask & SideBottomRight)) - continue; - } - - // get global x, y and z position - Double_t lDetElemGloX = 0.; - Double_t lDetElemGloY = 0.; - Double_t lDetElemGloZ = 0.; - - auto fTransform = fTransformCreator(lDetElemId); - o2::math_utils::Point3D SlatPos{0.0, 0.0, 0.0}; - o2::math_utils::Point3D GlobalPos; - - fTransform.LocalToMaster(SlatPos, GlobalPos); - lDetElemGloX = GlobalPos.x(); - lDetElemGloY = GlobalPos.y(); - lDetElemGloZ = GlobalPos.z(); - // fTransform->Local2Global(lDetElemId, 0, 0, 0, lDetElemGloX, lDetElemGloY, lDetElemGloZ); - - // increment mean Y, mean Z, sigmas and number of accepted detectors - lMeanY += lDetElemGloY; - lSigmaY += lDetElemGloY * lDetElemGloY; - lMeanZ += lDetElemGloZ; - lSigmaZ += lDetElemGloZ * lDetElemGloZ; - lNDetElem++; - } - - // calculate mean values - lMeanY /= lNDetElem; - lSigmaY /= lNDetElem; - lSigmaY = TMath::Sqrt(lSigmaY - lMeanY * lMeanY); - lMeanZ /= lNDetElem; - lSigmaZ /= lNDetElem; - lSigmaZ = TMath::Sqrt(lSigmaZ - lMeanZ * lMeanZ); - LOG(info) << "Used " << lNDetElem << " DetElem, MeanZ= " << lMeanZ << ", SigmaZ= " << lSigmaZ; - - // create all possible arrays - Array fConstraintX[4]; // Array for constraint equation X - Array fConstraintY[4]; // Array for constraint equation Y - Array fConstraintP[4]; // Array for constraint equation P - Array fConstraintXZ[4]; // Array for constraint equation X vs Z - Array fConstraintYZ[4]; // Array for constraint equation Y vs Z - Array fConstraintPZ[4]; // Array for constraint equation P vs Z - - // do we really need these ? - Array fConstraintXY[4]; // Array for constraint equation X vs Y - Array fConstraintYY[4]; // Array for constraint equation Y vs Y - Array fConstraintPY[4]; // Array for constraint equation P vs Y - - // fill Bool_t sides array based on masks, for convenience - Bool_t lDetTLBR[4]; - lDetTLBR[0] = sidesMask & SideTop; - lDetTLBR[1] = sidesMask & SideLeft; - lDetTLBR[2] = sidesMask & SideBottom; - lDetTLBR[3] = sidesMask & SideRight; - - for (Int_t i = 0; i < fgNDetElem; ++i) { - - // get chamber matching detector - const Int_t iCh(GetChamberId(i)); - - // skip detector if chamber is off - if (!lChOnOff[iCh - 1]) - continue; - - // get detector element id from detector element number - const Int_t lDetElemNumber = i - fgSNDetElemCh[iCh - 1]; - const Int_t lDetElemId = iCh * 100 + lDetElemNumber; - - // get global x, y and z position - Double_t lDetElemGloX = 0.; - Double_t lDetElemGloY = 0.; - Double_t lDetElemGloZ = 0.; - - auto fTransform = fTransformCreator(lDetElemId); - o2::math_utils::Point3D SlatPos{0.0, 0.0, 0.0}; - o2::math_utils::Point3D GlobalPos; - - fTransform.LocalToMaster(SlatPos, GlobalPos); - lDetElemGloX = GlobalPos.x(); - lDetElemGloY = GlobalPos.y(); - lDetElemGloZ = GlobalPos.z(); - // fTransform->Local2Global(lDetElemId, 0, 0, 0, lDetElemGloX, lDetElemGloY, lDetElemGloZ); - - // loop over sides - for (Int_t iSide = 0; iSide < 4; iSide++) { - - // skip if side is not selected - if (!lDetTLBR[iSide]) - continue; - - // skip detector if it is not in the selected side - // stations 1 and 2 - if (iCh >= 1 && iCh <= 4) { - if (lDetElemNumber == 0 && !(iSide == 0 || iSide == 3)) - continue; // top-right - if (lDetElemNumber == 1 && !(iSide == 0 || iSide == 1)) - continue; // top-left - if (lDetElemNumber == 2 && !(iSide == 2 || iSide == 1)) - continue; // bottom-left - if (lDetElemNumber == 3 && !(iSide == 2 || iSide == 3)) - continue; // bottom-right - } - - // station 3 - if (iCh >= 5 && iCh <= 6) { - if (lDetElemNumber >= 0 && lDetElemNumber <= 4 && !(iSide == 0 || iSide == 3)) - continue; // top-right - if (lDetElemNumber >= 5 && lDetElemNumber <= 9 && !(iSide == 0 || iSide == 1)) - continue; // top-left - if (lDetElemNumber >= 10 && lDetElemNumber <= 13 && !(iSide == 2 || iSide == 1)) - continue; // bottom-left - if (lDetElemNumber >= 14 && lDetElemNumber <= 17 && !(iSide == 2 || iSide == 3)) - continue; // bottom-right - } - - // stations 4 and 5 - if (iCh >= 7 && iCh <= 10) { - if (lDetElemNumber >= 0 && lDetElemNumber <= 6 && !(iSide == 0 || iSide == 3)) - continue; // top-right - if (lDetElemNumber >= 7 && lDetElemNumber <= 13 && !(iSide == 0 || iSide == 1)) - continue; // top-left - if (lDetElemNumber >= 14 && lDetElemNumber <= 19 && !(iSide == 2 || iSide == 1)) - continue; // bottom-left - if (lDetElemNumber >= 20 && lDetElemNumber <= 25 && !(iSide == 2 || iSide == 3)) - continue; // bottom-right - } - - // constrain x - if (lVarXYT[0]) - fConstraintX[iSide].values[i * fgNParCh + 0] = 1; - - // constrain y - if (lVarXYT[1]) - fConstraintY[iSide].values[i * fgNParCh + 1] = 1; - - // constrain phi (rotation around z) - if (lVarXYT[2]) - fConstraintP[iSide].values[i * fgNParCh + 2] = 1; - - // x-z shearing - if (lVarXYT[3]) - fConstraintXZ[iSide].values[i * fgNParCh + 0] = (lDetElemGloZ - lMeanZ) / lSigmaZ; - - // y-z shearing - if (lVarXYT[4]) - fConstraintYZ[iSide].values[i * fgNParCh + 1] = (lDetElemGloZ - lMeanZ) / lSigmaZ; - - // phi-z shearing - if (lVarXYT[5]) - fConstraintPZ[iSide].values[i * fgNParCh + 2] = (lDetElemGloZ - lMeanZ) / lSigmaZ; - - // x-y shearing - if (lVarXYT[6]) - fConstraintXY[iSide].values[i * fgNParCh + 0] = (lDetElemGloY - lMeanY) / lSigmaY; - - // y-y shearing - if (lVarXYT[7]) - fConstraintYY[iSide].values[i * fgNParCh + 1] = (lDetElemGloY - lMeanY) / lSigmaY; - - // phi-y shearing - if (lVarXYT[8]) - fConstraintPY[iSide].values[i * fgNParCh + 2] = (lDetElemGloY - lMeanY) / lSigmaY; - } - } - - // pass constraints to millepede - for (Int_t iSide = 0; iSide < 4; iSide++) { - // skip if side is not selected - if (!lDetTLBR[iSide]) - continue; - - if (lVarXYT[0]) - AddConstraint(fConstraintX[iSide].values, 0.0); - if (lVarXYT[1]) - AddConstraint(fConstraintY[iSide].values, 0.0); - if (lVarXYT[2]) - AddConstraint(fConstraintP[iSide].values, 0.0); - if (lVarXYT[3]) - AddConstraint(fConstraintXZ[iSide].values, 0.0); - if (lVarXYT[4]) - AddConstraint(fConstraintYZ[iSide].values, 0.0); - if (lVarXYT[5]) - AddConstraint(fConstraintPZ[iSide].values, 0.0); - if (lVarXYT[6]) - AddConstraint(fConstraintXY[iSide].values, 0.0); - if (lVarXYT[7]) - AddConstraint(fConstraintYY[iSide].values, 0.0); - if (lVarXYT[8]) - AddConstraint(fConstraintPY[iSide].values, 0.0); - } -} - -//______________________________________________________________________ -void Alignment::InitGlobalParameters(Double_t* par) -{ - /// Initialize global parameters with par array - if (!fInitialized) { - LOG(fatal) << "Millepede is not initialized"; - } - - fMillepede->SetGlobalParameters(par); -} - -//______________________________________________________________________ -void Alignment::SetAllowedVariation(Int_t iPar, Double_t value) -{ - /// "Encouraged" variation for degrees of freedom - // check initialization - if (fInitialized) { - LOG(fatal) << "Millepede already initialized"; - } - - // check initialization - if (!(iPar >= 0 && iPar < fgNParCh)) { - LOG(fatal) << "Invalid index: " << iPar; - } - - fAllowVar[iPar] = value; -} - -//______________________________________________________________________ -void Alignment::SetSigmaXY(Double_t sigmaX, Double_t sigmaY) -{ - - /// Set expected measurement resolution - fSigma[0] = sigmaX; - fSigma[1] = sigmaY; - - // print - for (Int_t i = 0; i < 2; ++i) { - LOG(info) << "fSigma[" << i << "] =" << fSigma[i]; - } -} - -//_____________________________________________________ -void Alignment::GlobalFit(Double_t* parameters, Double_t* errors, Double_t* pulls) -{ - - /// Call global fit; Global parameters are stored in parameters - fMillepede->GlobalFit(parameters, errors, pulls); - - LOG(info) << "Done fitting global parameters"; - for (int iDet = 0; iDet < fgNDetElem; ++iDet) { - LOG(info) << iDet << " " << parameters[iDet * fgNParCh + 0] << " " << parameters[iDet * fgNParCh + 1] << " " << parameters[iDet * fgNParCh + 3] << " " << parameters[iDet * fgNParCh + 2]; - } -} - -//_____________________________________________________ -void Alignment::PrintGlobalParameters() const -{ - fMillepede->PrintGlobalParameters(); -} - -//_____________________________________________________ -Double_t Alignment::GetParError(Int_t iPar) const -{ - return fMillepede->GetParError(iPar); -} - -// //______________________________________________________________________ -// AliMUONGeometryTransformer* Alignment::ReAlign( -// const AliMUONGeometryTransformer* transformer, -// const double* misAlignments, Bool_t) -// { - -// /// Returns a new AliMUONGeometryTransformer with the found misalignments -// /// applied. - -// // Takes the internal geometry module transformers, copies them -// // and gets the Detection Elements from them. -// // Takes misalignment parameters and applies these -// // to the local transform of the Detection Element -// // Obtains the global transform by multiplying the module transformer -// // transformation with the local transformation -// // Applies the global transform to a new detection element -// // Adds the new detection element to a new module transformer -// // Adds the new module transformer to a new geometry transformer -// // Returns the new geometry transformer - -// Double_t lModuleMisAlignment[fgNParCh] = {0}; -// Double_t lDetElemMisAlignment[fgNParCh] = {0}; -// const TClonesArray* oldMisAlignArray(transformer->GetMisAlignmentData()); - -// AliMUONGeometryTransformer* newGeometryTransformer = new AliMUONGeometryTransformer(); -// for (Int_t iMt = 0; iMt < transformer->GetNofModuleTransformers(); ++iMt) { - -// // module transformers -// const AliMUONGeometryModuleTransformer* kModuleTransformer = transformer->GetModuleTransformer(iMt, kTRUE); - -// AliMUONGeometryModuleTransformer* newModuleTransformer = new AliMUONGeometryModuleTransformer(iMt); -// newGeometryTransformer->AddModuleTransformer(newModuleTransformer); - -// // get transformation -// TGeoHMatrix deltaModuleTransform(DeltaTransform(lModuleMisAlignment)); - -// // update module -// TGeoHMatrix moduleTransform(*kModuleTransformer->GetTransformation()); -// TGeoHMatrix newModuleTransform(AliMUONGeometryBuilder::Multiply(deltaModuleTransform, moduleTransform)); -// newModuleTransformer->SetTransformation(newModuleTransform); - -// // Get matching old alignment and update current matrix accordingly -// if (oldMisAlignArray) { - -// const AliAlignObjMatrix* oldAlignObj(0); -// const Int_t moduleId(kModuleTransformer->GetModuleId()); -// const Int_t volId = AliGeomManager::LayerToVolUID(AliGeomManager::kMUON, moduleId); -// for (Int_t pos = 0; pos < oldMisAlignArray->GetEntriesFast(); ++pos) { - -// const AliAlignObjMatrix* localAlignObj(dynamic_cast(oldMisAlignArray->At(pos))); -// if (localAlignObj && localAlignObj->GetVolUID() == volId) { -// oldAlignObj = localAlignObj; -// break; -// } -// } - -// // multiply -// if (oldAlignObj) { - -// TGeoHMatrix oldMatrix; -// oldAlignObj->GetMatrix(oldMatrix); -// deltaModuleTransform.Multiply(&oldMatrix); -// } -// } - -// // Create module mis alignment matrix -// newGeometryTransformer->AddMisAlignModule(kModuleTransformer->GetModuleId(), deltaModuleTransform); - -// AliMpExMap* detElements = kModuleTransformer->GetDetElementStore(); - -// TIter next(detElements->CreateIterator()); -// AliMUONGeometryDetElement* detElement; -// Int_t iDe(-1); -// while ((detElement = static_cast(next()))) { -// ++iDe; -// // make a new detection element -// AliMUONGeometryDetElement* newDetElement = new AliMUONGeometryDetElement(detElement->GetId(), detElement->GetVolumePath()); -// TString lDetElemName(detElement->GetDEName()); -// lDetElemName.ReplaceAll("DE", ""); - -// // store detector element id and number -// const Int_t iDetElemId = lDetElemName.Atoi(); -// if (DetElemIsValid(iDetElemId)) { - -// const Int_t iDetElemNumber(GetDetElemNumber(iDetElemId)); - -// for (int i = 0; i < fgNParCh; ++i) { -// lDetElemMisAlignment[i] = 0.0; -// if (iMt < fgNTrkMod) { -// lDetElemMisAlignment[i] = misAlignments[iDetElemNumber * fgNParCh + i]; -// } -// } - -// // get transformation -// TGeoHMatrix deltaGlobalTransform(DeltaTransform(lDetElemMisAlignment)); - -// // update module -// TGeoHMatrix globalTransform(*detElement->GetGlobalTransformation()); -// TGeoHMatrix newGlobalTransform(AliMUONGeometryBuilder::Multiply(deltaGlobalTransform, globalTransform)); -// newDetElement->SetGlobalTransformation(newGlobalTransform); -// newModuleTransformer->GetDetElementStore()->Add(newDetElement->GetId(), newDetElement); - -// // Get matching old alignment and update current matrix accordingly -// if (oldMisAlignArray) { - -// const AliAlignObjMatrix* oldAlignObj(0); -// const int detElemId(detElement->GetId()); -// const Int_t volId = AliGeomManager::LayerToVolUID(AliGeomManager::kMUON, detElemId); -// for (Int_t pos = 0; pos < oldMisAlignArray->GetEntriesFast(); ++pos) { - -// const AliAlignObjMatrix* localAlignObj(dynamic_cast(oldMisAlignArray->At(pos))); -// if (localAlignObj && localAlignObj->GetVolUID() == volId) { -// oldAlignObj = localAlignObj; -// break; -// } -// } - -// // multiply -// if (oldAlignObj) { - -// TGeoHMatrix oldMatrix; -// oldAlignObj->GetMatrix(oldMatrix); -// deltaGlobalTransform.Multiply(&oldMatrix); -// } -// } - -// // Create misalignment matrix -// newGeometryTransformer->AddMisAlignDetElement(detElement->GetId(), deltaGlobalTransform); - -// } else { - -// // "invalid" detector elements come from MTR and are left unchanged -// Aliinfo(Form("Keeping detElement %i unchanged", iDetElemId)); - -// // update module -// TGeoHMatrix globalTransform(*detElement->GetGlobalTransformation()); -// newDetElement->SetGlobalTransformation(globalTransform); -// newModuleTransformer->GetDetElementStore()->Add(newDetElement->GetId(), newDetElement); - -// // Get matching old alignment and update current matrix accordingly -// if (oldMisAlignArray) { - -// const AliAlignObjMatrix* oldAlignObj(0); -// const int detElemId(detElement->GetId()); -// const Int_t volId = AliGeomManager::LayerToVolUID(AliGeomManager::kMUON, detElemId); -// for (Int_t pos = 0; pos < oldMisAlignArray->GetEntriesFast(); ++pos) { - -// const AliAlignObjMatrix* localAlignObj(dynamic_cast(oldMisAlignArray->At(pos))); -// if (localAlignObj && localAlignObj->GetVolUID() == volId) { -// oldAlignObj = localAlignObj; -// break; -// } -// } - -// // multiply -// if (oldAlignObj) { - -// TGeoHMatrix oldMatrix; -// oldAlignObj->GetMatrix(oldMatrix); -// newGeometryTransformer->AddMisAlignDetElement(detElement->GetId(), oldMatrix); -// } -// } -// } -// } - -// newGeometryTransformer->AddModuleTransformer(newModuleTransformer); -// } - -// return newGeometryTransformer; -// } - -//______________________________________________________________________ -void Alignment::SetAlignmentResolution(const TClonesArray* misAlignArray, Int_t rChId, Double_t chResX, Double_t chResY, Double_t deResX, Double_t deResY) -{ - - /// Set alignment resolution to misalign objects to be stored in CDB - /// if rChId is > 0 set parameters for this chamber only, counting from 1 - TMatrixDSym mChCorrMatrix(6); - mChCorrMatrix[0][0] = chResX * chResX; - mChCorrMatrix[1][1] = chResY * chResY; - - TMatrixDSym mDECorrMatrix(6); - mDECorrMatrix[0][0] = deResX * deResX; - mDECorrMatrix[1][1] = deResY * deResY; - - o2::detectors::AlignParam* alignMat = 0x0; - - for (Int_t chId = 0; chId <= 9; ++chId) { - - // skip chamber if selection is valid, and does not match - if (rChId > 0 && chId + 1 != rChId) - continue; - - TString chName1; - TString chName2; - if (chId < 4) { - - chName1 = Form("GM%d", chId); - chName2 = Form("GM%d", chId); - - } else { - - chName1 = Form("GM%d", 4 + (chId - 4) * 2); - chName2 = Form("GM%d", 4 + (chId - 4) * 2 + 1); - } - - for (int i = 0; i < misAlignArray->GetEntries(); ++i) { - - alignMat = (o2::detectors::AlignParam*)misAlignArray->At(i); - TString volName(alignMat->getSymName()); - if ((volName.Contains(chName1) && - ((volName.Last('/') == volName.Index(chName1) + chName1.Length()) || - (volName.Length() == volName.Index(chName1) + chName1.Length()))) || - (volName.Contains(chName2) && - ((volName.Last('/') == volName.Index(chName2) + chName2.Length()) || - (volName.Length() == volName.Index(chName2) + chName2.Length())))) { - - volName.Remove(0, volName.Last('/') + 1); - // if (volName.Contains("GM")){ - // alignMat->SetCorrMatrix(mChCorrMatrix); - // }else if (volName.Contains("DE")){ - // alignMat->SetCorrMatrix(mDECorrMatrix); - // } - } - } - } -} - -//_____________________________________________________ -LocalTrackParam Alignment::RefitStraightTrack(Track& track, Double_t z0) const -{ - - // initialize matrices - TMatrixD AtGASum(4, 4); - AtGASum.Zero(); - - TMatrixD AtGMSum(4, 1); - AtGMSum.Zero(); - - // loop over clusters - for (auto itTrackParam(track.begin()); itTrackParam != track.end(); ++itTrackParam) { - - // get track parameters - if (!&*itTrackParam) - continue; - - // get cluster - const Cluster* cluster = itTrackParam->getClusterPtr(); - if (!cluster) - continue; - - // projection matrix - TMatrixD A(2, 4); - A.Zero(); - A(0, 0) = 1; - A(0, 2) = (cluster->getZ() - z0); - A(1, 1) = 1; - A(1, 3) = (cluster->getZ() - z0); - - TMatrixD At(TMatrixD::kTransposed, A); - - // gain matrix - TMatrixD G(2, 2); - G.Zero(); - G(0, 0) = 1.0 / Square(cluster->getEx()); - G(1, 1) = 1.0 / Square(cluster->getEy()); - - const TMatrixD AtG(At, TMatrixD::kMult, G); - const TMatrixD AtGA(AtG, TMatrixD::kMult, A); - AtGASum += AtGA; - - // measurement - TMatrixD M(2, 1); - M(0, 0) = cluster->getX(); - M(1, 0) = cluster->getY(); - const TMatrixD AtGM(AtG, TMatrixD::kMult, M); - AtGMSum += AtGM; - } - - // perform inversion - TMatrixD AtGASumInv(TMatrixD::kInverted, AtGASum); - TMatrixD X(AtGASumInv, TMatrixD::kMult, AtGMSum); - - // // TODO: compare with initial track parameters - // Aliinfo( Form( "x: %.3f vs %.3f", fTrackPos0[0], X(0,0) ) ); - // Aliinfo( Form( "y: %.3f vs %.3f", fTrackPos0[1], X(1,0) ) ); - // Aliinfo( Form( "dxdz: %.6g vs %.6g", fTrackSlope0[0], X(2,0) ) ); - // Aliinfo( Form( "dydz: %.6g vs %.6g\n", fTrackSlope0[1], X(3,0) ) ); - - // fill output parameters - LocalTrackParam out; - out.fTrackX = X(0, 0); - out.fTrackY = X(1, 0); - out.fTrackZ = z0; - out.fTrackSlopeX = X(2, 0); - out.fTrackSlopeY = X(3, 0); - - return out; -} - -//_____________________________________________________ -void Alignment::FillDetElemData(const Cluster* cluster) -{ - // LOG(fatal) << __PRETTY_FUNCTION__ << " is disabled"; - LOG(info) << __PRETTY_FUNCTION__ << " is enabled"; - - /// Get information of current detection element - // get detector element number from Alice ID - const Int_t detElemId = cluster->getDEId(); - fDetElemNumber = GetDetElemNumber(detElemId); - - // get detector element - // const AliMUONGeometryDetElement detElement(detElemId); - auto fTransform = fTransformCreator(detElemId); - /* - get the global transformation matrix and store its inverse, in order to manually perform - the global to Local transformations needed to calculate the derivatives - */ - // fTransform = fTransform.Inverse(); - // fTransform.GetTransformMatrix(fGeoCombiTransInverse); -} - -//______________________________________________________________________ -void Alignment::FillRecPointData(const Cluster* cluster) -{ - - /// Get information of current cluster - fClustPos[0] = cluster->getX(); - fClustPos[1] = cluster->getY(); - fClustPos[2] = cluster->getZ(); -} - -//______________________________________________________________________ -void Alignment::FillTrackParamData(const TrackParam* trackParam) -{ - - /// Get information of current track at current cluster - fTrackPos[0] = trackParam->getNonBendingCoor(); - fTrackPos[1] = trackParam->getBendingCoor(); - fTrackPos[2] = trackParam->getZ(); - fTrackSlope[0] = trackParam->getNonBendingSlope(); - fTrackSlope[1] = trackParam->getBendingSlope(); -} - -//______________________________________________________________________ -void Alignment::LocalEquationX(void) -{ - /// local equation along X - - // 'inverse' (GlobalToLocal) rotation matrix - const Double_t* r(fGeoCombiTransInverse.GetRotationMatrix()); - - // local derivatives - SetLocalDerivative(0, r[0]); - SetLocalDerivative(1, r[0] * (fTrackPos[2] - fTrackPos0[2])); - SetLocalDerivative(2, r[1]); - SetLocalDerivative(3, r[1] * (fTrackPos[2] - fTrackPos0[2])); - - // global derivatives - /* - alignment parameters are - 0: delta_x - 1: delta_y - 2: delta_phiz - 3: delta_z - */ - - SetGlobalDerivative(fDetElemNumber * fgNParCh + 0, -r[0]); - SetGlobalDerivative(fDetElemNumber * fgNParCh + 1, -r[1]); - - if (fBFieldOn) { - - // use local position for derivatives vs 'delta_phi_z' - SetGlobalDerivative(fDetElemNumber * fgNParCh + 2, -r[1] * fTrackPos[0] + r[0] * fTrackPos[1]); - - // use local slopes for derivatives vs 'delta_z' - SetGlobalDerivative(fDetElemNumber * fgNParCh + 3, r[0] * fTrackSlope[0] + r[1] * fTrackSlope[1]); - - } else { - - // local copy of extrapolated track positions - const Double_t trackPosX = fTrackPos0[0] + fTrackSlope0[0] * (fTrackPos[2] - fTrackPos0[2]); - const Double_t trackPosY = fTrackPos0[1] + fTrackSlope0[1] * (fTrackPos[2] - fTrackPos0[2]); - - // use properly extrapolated position for derivatives vs 'delta_phi_z' - SetGlobalDerivative(fDetElemNumber * fgNParCh + 2, -r[1] * trackPosX + r[0] * trackPosY); - - // use slopes at origin for derivatives vs 'delta_z' - SetGlobalDerivative(fDetElemNumber * fgNParCh + 3, r[0] * fTrackSlope0[0] + r[1] * fTrackSlope0[1]); - } - - // store local equation - fMillepede->SetLocalEquation(fGlobalDerivatives, fLocalDerivatives, fMeas[0], fSigma[0]); -} - -//______________________________________________________________________ -void Alignment::LocalEquationY(void) -{ - /// local equation along Y - - // 'inverse' (GlobalToLocal) rotation matrix - const Double_t* r(fGeoCombiTransInverse.GetRotationMatrix()); - - // store local derivatives - SetLocalDerivative(0, r[3]); - SetLocalDerivative(1, r[3] * (fTrackPos[2] - fTrackPos0[2])); - SetLocalDerivative(2, r[4]); - SetLocalDerivative(3, r[4] * (fTrackPos[2] - fTrackPos0[2])); - - // set global derivatives - SetGlobalDerivative(fDetElemNumber * fgNParCh + 0, -r[3]); - SetGlobalDerivative(fDetElemNumber * fgNParCh + 1, -r[4]); - - if (fBFieldOn) { - - // use local position for derivatives vs 'delta_phi' - SetGlobalDerivative(fDetElemNumber * fgNParCh + 2, -r[4] * fTrackPos[0] + r[3] * fTrackPos[1]); - - // use local slopes for derivatives vs 'delta_z' - SetGlobalDerivative(fDetElemNumber * fgNParCh + 3, r[3] * fTrackSlope[0] + r[4] * fTrackSlope[1]); - - } else { - - // local copy of extrapolated track positions - const Double_t trackPosX = fTrackPos0[0] + fTrackSlope0[0] * (fTrackPos[2] - fTrackPos0[2]); - const Double_t trackPosY = fTrackPos0[1] + fTrackSlope0[1] * (fTrackPos[2] - fTrackPos0[2]); - - // use properly extrapolated position for derivatives vs 'delta_phi' - SetGlobalDerivative(fDetElemNumber * fgNParCh + 2, -r[4] * trackPosX + r[3] * trackPosY); - - // use slopes at origin for derivatives vs 'delta_z' - SetGlobalDerivative(fDetElemNumber * fgNParCh + 3, r[3] * fTrackSlope0[0] + r[4] * fTrackSlope0[1]); - } - - // store local equation - fMillepede->SetLocalEquation(fGlobalDerivatives, fLocalDerivatives, fMeas[1], fSigma[1]); -} - -//_________________________________________________________________________ -TGeoCombiTrans Alignment::DeltaTransform(const double* lMisAlignment) const -{ - /// Get Delta Transformation, based on alignment parameters - - // translation - const TGeoTranslation deltaTrans(lMisAlignment[0], lMisAlignment[1], lMisAlignment[3]); - - // rotation - TGeoRotation deltaRot; - deltaRot.RotateZ(lMisAlignment[2] * 180. / TMath::Pi()); - - // combined rotation and translation. - return TGeoCombiTrans(deltaTrans, deltaRot); -} - -//______________________________________________________________________ -void Alignment::AddConstraint(Double_t* par, Double_t value) -{ - /// Constrain equation defined by par to value - if (!fInitialized) { - LOG(fatal) << "Millepede is not initialized"; - } - - fMillepede->SetGlobalConstraint(par, value); -} - -//______________________________________________________________________ -Bool_t Alignment::DetElemIsValid(Int_t iDetElemId) const -{ - /// return true if given detector element is valid (and belongs to muon tracker) - const Int_t iCh = iDetElemId / 100; - const Int_t iDet = iDetElemId % 100; - return (iCh > 0 && iCh <= fgNCh && iDet < fgNDetElemCh[iCh - 1]); -} - -//______________________________________________________________________ -Int_t Alignment::GetDetElemNumber(Int_t iDetElemId) const -{ - /// get det element number from ID - // get chamber and element number in chamber - const Int_t iCh = iDetElemId / 100; - const Int_t iDet = iDetElemId % 100; - - // make sure detector index is valid - if (!(iCh > 0 && iCh <= fgNCh && iDet < fgNDetElemCh[iCh - 1])) { - LOG(fatal) << "Invalid detector element id: " << iDetElemId; - } - - // add number of detectors up to this chamber - return iDet + fgSNDetElemCh[iCh - 1]; -} - -//______________________________________________________________________ -Int_t Alignment::GetChamberId(Int_t iDetElemNumber) const -{ - /// get chamber (counting from 1) matching a given detector element id - Int_t iCh(0); - for (iCh = 0; iCh < fgNCh; iCh++) { - if (iDetElemNumber < fgSNDetElemCh[iCh]) - break; - } - - return iCh; -} - -//______________________________________________________________________ -TString Alignment::GetParameterMaskString(UInt_t mask) const -{ - TString out; - if (mask & ParX) - out += "X"; - if (mask & ParY) - out += "Y"; - if (mask & ParZ) - out += "Z"; - if (mask & ParTZ) - out += "T"; - return out; -} - -//______________________________________________________________________ -TString Alignment::GetSidesMaskString(UInt_t mask) const -{ - TString out; - if (mask & SideTop) - out += "T"; - if (mask & SideLeft) - out += "L"; - if (mask & SideBottom) - out += "B"; - if (mask & SideRight) - out += "R"; - return out; -} - -} // namespace mch -} // namespace o2 \ No newline at end of file diff --git a/Detectors/ITSMFT/MFT/calibration/src/NoiseSlotCalibrator.cxx b/Detectors/ITSMFT/MFT/calibration/src/NoiseSlotCalibrator.cxx deleted file mode 100644 index 13d6f3b3f567b..0000000000000 --- a/Detectors/ITSMFT/MFT/calibration/src/NoiseSlotCalibrator.cxx +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file NoiseSlotCalibrator.cxx - -#include "MFTCalibration/NoiseSlotCalibrator.h" - -#include -#include "TFile.h" -#include "DataFormatsITSMFT/Digit.h" -#include "DataFormatsITSMFT/ClusterPattern.h" -#include "DataFormatsITSMFT/ROFRecord.h" - -namespace o2 -{ -using Slot = calibration::TimeSlot; - -namespace mft -{ -bool NoiseSlotCalibrator::processTimeFrame(calibration::TFType nTF, - gsl::span const& digits, - gsl::span const& rofs) -{ - LOG(detail) << "Processing TF# " << nTF; - - auto& slotTF = getSlotForTF(nTF); - auto& noiseMap = *(slotTF.getContainer()); - - for (const auto& rof : rofs) { - auto digitsInFrame = rof.getROFData(digits); - for (const auto& d : digitsInFrame) { - auto id = d.getChipIndex(); - auto row = d.getRow(); - auto col = d.getColumn(); - - noiseMap.increaseNoiseCount(id, row, col); - } - } - noiseMap.addStrobes(rofs.size()); - mNumberOfStrobes += rofs.size(); - return hasEnoughData(slotTF); -} - -bool NoiseSlotCalibrator::processTimeFrame(calibration::TFType nTF, - gsl::span const& clusters, - gsl::span const& patterns, - gsl::span const& rofs) -{ - LOG(detail) << "Processing TF# " << nTF; - - auto& slotTF = getSlotForTF(nTF); - auto& noiseMap = *(slotTF.getContainer()); - - auto pattIt = patterns.begin(); - for (const auto& rof : rofs) { - auto clustersInFrame = rof.getROFData(clusters); - for (const auto& c : clustersInFrame) { - if (c.getPatternID() != o2::itsmft::CompCluster::InvalidPatternID) { - // For the noise calibration, we use "pass1" clusters... - continue; - } - o2::itsmft::ClusterPattern patt(pattIt); - - auto id = c.getSensorID(); - auto row = c.getRow(); - auto col = c.getCol(); - auto colSpan = patt.getColumnSpan(); - auto rowSpan = patt.getRowSpan(); - - // Fast 1-pixel calibration - if ((rowSpan == 1) && (colSpan == 1)) { - noiseMap.increaseNoiseCount(id, row, col); - continue; - } - - // All-pixel calibration - auto nBits = rowSpan * colSpan; - int ic = 0, ir = 0; - for (unsigned int i = 2; i < patt.getUsedBytes() + 2; i++) { - unsigned char tempChar = patt.getByte(i); - int s = 128; // 0b10000000 - while (s > 0) { - if ((tempChar & s) != 0) { - noiseMap.increaseNoiseCount(id, row + ir, col + ic); - } - ic++; - s >>= 1; - if ((ir + 1) * ic == nBits) { - break; - } - if (ic == colSpan) { - ic = 0; - ir++; - } - } - if ((ir + 1) * ic == nBits) { - break; - } - } - } - } - noiseMap.addStrobes(rofs.size()); - mNumberOfStrobes += rofs.size(); - return hasEnoughData(slotTF); -} - -// Functions overloaded from the calibration framework -bool NoiseSlotCalibrator::process(calibration::TFType tf, const gsl::span data) -{ - LOG(warning) << "Only 1-pix noise calibraton is possible !"; - return calibration::TimeSlotCalibration::process(tf, data); -} - -// Functions required by the calibration framework - -Slot& NoiseSlotCalibrator::emplaceNewSlot(bool front, calibration::TFType tstart, calibration::TFType tend) -{ - auto& cont = getSlots(); - auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); - slot.setContainer(std::make_unique(936)); - return slot; -} - -bool NoiseSlotCalibrator::hasEnoughData(const Slot& slot) const -{ - return slot.getContainer()->getNumberOfStrobes() > mMinROFs ? true : false; -} - -void NoiseSlotCalibrator::finalizeSlot(Slot& slot) -{ - o2::itsmft::NoiseMap* map = slot.getContainer(); - LOG(info) << "Number of processed strobes is " << map->getNumberOfStrobes(); - map->applyProbThreshold(mProbabilityThreshold, map->getNumberOfStrobes(), mProbRelErr); -} - -} // namespace mft -} // namespace o2 From 6d11591da421e8c200b3368a41727752882e4db1 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Wed, 11 Feb 2026 10:09:52 +0100 Subject: [PATCH 188/234] ITS: GPU: use mean vertex constraint for gpu processing I noticed that in the Pb-Pb production we did not add the mean vertex constraint to be used. --- prodtests/full-system-test/dpl-workflow.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index f559fcdf91cf5..a8f01a3ef1822 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -572,6 +572,9 @@ if [[ $CTFINPUT == 0 && $DIGITINPUT == 0 ]]; then fi has_detector_gpu ITS && GPU_INPUT+=",its-clusters" +if [[ $BEAMTYPE != "cosmic" && $SYNCMODE != 1 ]]; then + has_detector_gpu ITS && GPU_INPUT+=",its-mean-vertex" +fi has_detector_gpu ITS && GPU_OUTPUT+=",its-tracks" # --------------------------------------------------------------------------------------------------------------------- From 7c79e17a0c694491c65c3033f976084f85cca8d7 Mon Sep 17 00:00:00 2001 From: Matthias Kleiner Date: Wed, 11 Feb 2026 09:44:56 +0100 Subject: [PATCH 189/234] TPC: time gain calibration optimizations - bug fix: using bin centre of the dE/dx instead of lower bin edge - add option to not perform per sector scaling (needed for MC) --- .../DataFormatsTPC/CalibdEdxCorrection.h | 3 +++ .../Detectors/TPC/src/CalibdEdxCorrection.cxx | 13 +++++++++++++ .../include/TPCCalibration/CalibdEdx.h | 4 +++- Detectors/TPC/calibration/src/CalibdEdx.cxx | 17 +++++++++++------ 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/CalibdEdxCorrection.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CalibdEdxCorrection.h index 1d7b10dc965f7..024d6189593e9 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/CalibdEdxCorrection.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CalibdEdxCorrection.h @@ -115,6 +115,9 @@ class CalibdEdxCorrection /// Single fit parameters averaged over all sectors for a stack type float getMeanEntries(const GEMstack stack, ChargeType charge) const; + /// set all corrections to 1, used for default initialization and to reset corrections + void setUnity(); + #endif private: diff --git a/DataFormats/Detectors/TPC/src/CalibdEdxCorrection.cxx b/DataFormats/Detectors/TPC/src/CalibdEdxCorrection.cxx index 0991c8693d8e8..152feacb41937 100644 --- a/DataFormats/Detectors/TPC/src/CalibdEdxCorrection.cxx +++ b/DataFormats/Detectors/TPC/src/CalibdEdxCorrection.cxx @@ -168,3 +168,16 @@ float CalibdEdxCorrection::getMeanEntries(const GEMstack stack, ChargeType charg return mean / (SECTORSPERSIDE * SIDES); } + +void CalibdEdxCorrection::setUnity() +{ + for (int i = 0; i < FitSize; ++i) { + for (int j = 0; j < ParamSize; ++j) { + mParams[i][j] = 0.f; + } + mParams[i][0] = 1.f; // constant term = 1 + mChi2[i] = 0.f; + mEntries[i] = 0; + } + mDims = 0; +} diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibdEdx.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibdEdx.h index 20e470702a89a..ff7c763efcd2b 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibdEdx.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibdEdx.h @@ -129,7 +129,9 @@ class CalibdEdx /// Compute MIP position from dEdx histograms and save result in the correction container. /// To retrieve the correction call `CalibdEdx::getCalib()` /// \param useGausFits make gaussian fits of dEdx vs tgl instead of fitting the mean dEdx - void finalize(const bool useGausFits = true); + /// \param averageSectors If true, the correction is averaged over all sectors. + /// In this case, no mean-sector scaling is applied when statistics are low. + void finalize(const bool useGausFits = true, const bool averageSectors = false); /// Return calib data histogram const Hist& getHist() const { return mHist; } diff --git a/Detectors/TPC/calibration/src/CalibdEdx.cxx b/Detectors/TPC/calibration/src/CalibdEdx.cxx index 4eb29c8833565..938ab8ae91065 100644 --- a/Detectors/TPC/calibration/src/CalibdEdx.cxx +++ b/Detectors/TPC/calibration/src/CalibdEdx.cxx @@ -351,7 +351,7 @@ auto ProjectBoostHistoXFastAllSectors(const Hist& hist, std::vector& bin_in // access the bin content specified by bin_indices const float counts = hist.at(bin_indices); - float dEdx = hist.axis(ax::dEdx).value(i); + float dEdx = hist.axis(ax::dEdx).bin(i).center(); // scale the dedx to the mean if (stackMean != nullptr) { @@ -532,7 +532,7 @@ void CalibdEdx::fitHistGaus(TLinearFitter& fitter, CalibdEdxCorrection& corr, co LOGP(info, "Calibration fits took: {}", time.count()); } -void CalibdEdx::finalize(const bool useGausFits) +void CalibdEdx::finalize(const bool useGausFits, const bool averageSectors) { const float entries = minStackEntries(); mCalib.clear(); @@ -565,10 +565,15 @@ void CalibdEdx::finalize(const bool useGausFits) // get mean of each GEM stack CalibdEdxCorrection meanCorr{}; meanCorr.setDims(0); - TLinearFitter meanFitter(0); - meanFitter.SetFormula("1"); - // get the mean dEdx for each stack - fitHist(mHist, meanCorr, meanFitter, mFitCut, mFitLowCutFactor, mFitPasses); + if (averageSectors) { + // set mean dEdx per stack to unity + meanCorr.setUnity(); + } else { + // get the mean dEdx for each stack + TLinearFitter meanFitter(0); + meanFitter.SetFormula("1"); + fitHist(mHist, meanCorr, meanFitter, mFitCut, mFitLowCutFactor, mFitPasses, nullptr, mDebugOutputStreamer.get()); + } if (!useGausFits) { // get higher dimension corrections with projected sectors fitHist(mHist, mCalib, fitter, mFitCut, mFitLowCutFactor, mFitPasses, &meanCorr, mDebugOutputStreamer.get()); From a1b356bc9af763d7c8bd7893f04b17d7202f8457 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 12 Feb 2026 00:11:38 +0100 Subject: [PATCH 190/234] GPU Vulkan Display: fix DEPFILE path --- GPU/GPUTracking/cmake/vulkan_display.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GPUTracking/cmake/vulkan_display.cmake b/GPU/GPUTracking/cmake/vulkan_display.cmake index 7cbfd0328c323..7859742363755 100644 --- a/GPU/GPUTracking/cmake/vulkan_display.cmake +++ b/GPU/GPUTracking/cmake/vulkan_display.cmake @@ -27,7 +27,7 @@ function(add_glslc_shader TARGET SHADER) OUTPUT ${spirv-file} COMMAND ${Vulkan_GLSLC_EXECUTABLE} -o ${spirv-file} ${input-file-abs} -MD -MT ${spirv-file} -MF ${spirv-file}.d DEPENDS ${input-file-abs} - DEPFILE ${input-file-abs}.d + DEPFILE ${spirv-file}.d COMMENT "Compiling GLSL to SPIRV: ${SHADER}" VERBATIM ) From bf2a3feb26a00127d99b08b9185b3a7a1fc30e15 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 11 Feb 2026 15:52:03 +0100 Subject: [PATCH 191/234] DCS: Fix undefined behavior and invalid pointer access --- Detectors/DCS/src/DataPointCreator.cxx | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Detectors/DCS/src/DataPointCreator.cxx b/Detectors/DCS/src/DataPointCreator.cxx index 06b0321ad2c94..0bfb5bcd7d387 100644 --- a/Detectors/DCS/src/DataPointCreator.cxx +++ b/Detectors/DCS/src/DataPointCreator.cxx @@ -37,10 +37,9 @@ DataPointCompositeObject createDataPointCompositeObject(const std::string& alias template <> DataPointCompositeObject createDataPointCompositeObject(const std::string& alias, float val, uint32_t seconds, uint16_t msec, uint16_t flags) { - float tmp[2]; - tmp[0] = val; - tmp[1] = 0; - return createDPCOM(alias, reinterpret_cast(&tmp[0]), seconds, msec, flags, DeliveryType::DPVAL_FLOAT); + uint64_t tmp = 0; + memcpy(&tmp, &val, sizeof(val)); + return createDPCOM(alias, &tmp, seconds, msec, flags, DeliveryType::DPVAL_FLOAT); } template <> @@ -54,36 +53,38 @@ template <> DataPointCompositeObject createDataPointCompositeObject(const std::string& alias, uint32_t val, uint32_t seconds, uint16_t msec, uint16_t flags) { uint64_t tmp{val}; - return createDPCOM(alias, reinterpret_cast(&tmp), seconds, msec, flags, DeliveryType::DPVAL_UINT); + return createDPCOM(alias, &tmp, seconds, msec, flags, DeliveryType::DPVAL_UINT); } template <> DataPointCompositeObject createDataPointCompositeObject(const std::string& alias, long long val, uint32_t seconds, uint16_t msec, uint16_t flags) { uint64_t tmp{static_cast(val)}; - return createDPCOM(alias, reinterpret_cast(&tmp), seconds, msec, flags, DeliveryType::DPVAL_UINT); + return createDPCOM(alias, &tmp, seconds, msec, flags, DeliveryType::DPVAL_UINT); } template <> DataPointCompositeObject createDataPointCompositeObject(const std::string& alias, char val, uint32_t seconds, uint16_t msec, uint16_t flags) { - return createDPCOM(alias, reinterpret_cast(&val), seconds, msec, flags, DeliveryType::DPVAL_CHAR); + uint64_t tmp = 0; + memcpy(&tmp, &val, 1); + return createDPCOM(alias, &tmp, seconds, msec, flags, DeliveryType::DPVAL_CHAR); } template <> DataPointCompositeObject createDataPointCompositeObject(const std::string& alias, bool val, uint32_t seconds, uint16_t msec, uint16_t flags) { uint64_t tmp{val}; - return createDPCOM(alias, reinterpret_cast(&tmp), seconds, msec, flags, DeliveryType::DPVAL_BOOL); + return createDPCOM(alias, &tmp, seconds, msec, flags, DeliveryType::DPVAL_BOOL); } template <> DataPointCompositeObject createDataPointCompositeObject(const std::string& alias, std::string val, uint32_t seconds, uint16_t msec, uint16_t flags) { constexpr int N{56}; - char str[N]; - strncpy(str, val.c_str(), N); - return createDPCOM(alias, reinterpret_cast(&str[0]), seconds, msec, flags, DeliveryType::DPVAL_STRING); + uint64_t tmp[N / sizeof(uint64_t)]; + strncpy((char*)tmp, val.c_str(), N); + return createDPCOM(alias, tmp, seconds, msec, flags, DeliveryType::DPVAL_STRING); } } // namespace o2::dcs From 6ef43cf21196279d3c6e7cb507e51e4274b015ac Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Thu, 12 Feb 2026 09:01:29 +0100 Subject: [PATCH 192/234] ITS3: load chip response functions from ccdb (#15051) Signed-off-by: Felix Schlepper --- .../ITS3/macros/test/CheckChipResponseFile.C | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/Detectors/Upgrades/ITS3/macros/test/CheckChipResponseFile.C b/Detectors/Upgrades/ITS3/macros/test/CheckChipResponseFile.C index 32d5bad87ce21..5bc053c516079 100644 --- a/Detectors/Upgrades/ITS3/macros/test/CheckChipResponseFile.C +++ b/Detectors/Upgrades/ITS3/macros/test/CheckChipResponseFile.C @@ -22,6 +22,7 @@ #include #include +#include "CCDB/BasicCCDBManager.h" #define ENABLE_UPGRADES #include "ITSMFTSimulation/AlpideSimResponse.h" #include "ITS3Simulation/ChipSimResponse.h" @@ -37,16 +38,12 @@ double cm2um(double cm) { return cm * 1e+4; } std::unique_ptr mAlpSimResp0, mAlpSimResp1, mAptSimResp1; -std::unique_ptr loadResponse(const std::string& fileName, const std::string& respName) +std::unique_ptr loadResponse(const std::string& path) { - TFile* f = TFile::Open(fileName.data()); - if (!f) { - std::cerr << fileName << " not found" << std::endl; - return nullptr; - } - auto base = f->Get(respName.c_str()); + auto& cdb = o2::ccdb::BasicCCDBManager::instance(); + o2::itsmft::AlpideSimResponse* base = cdb.get(path); if (!base) { - std::cerr << respName << " not found in " << fileName << std::endl; + std::cerr << path << " not found in " << '\n'; return nullptr; } return std::make_unique(base); @@ -54,24 +51,24 @@ std::unique_ptr loadResponse(const std::string& fileN void LoadRespFunc() { - std::string AptsFile = "$(O2_ROOT)/share/Detectors/Upgrades/ITS3/data/ITS3ChipResponseData/APTSResponseData.root"; - std::string AlpideFile = "$(O2_ROOT)/share/Detectors/ITSMFT/data/AlpideResponseData/AlpideResponseData.root"; + auto& cdb = o2::ccdb::BasicCCDBManager::instance(); + cdb.setURL("https://alice-ccdb.cern.ch/"); std::cout << "=====================\n"; LOGP(info, "ALPIDE Vbb=0V response"); - mAlpSimResp0 = loadResponse(AlpideFile, "response0"); // Vbb=0V + mAlpSimResp0 = loadResponse("ITSMFT/Calib/ALPIDEResponseVbb0"); // Vbb=0V mAlpSimResp0->computeCentreFromData(); mAlpSimResp0->print(); LOGP(info, "Response Centre {}", mAlpSimResp0->getRespCentreDep()); std::cout << "=====================\n"; LOGP(info, "ALPIDE Vbb=-3V response"); - mAlpSimResp1 = loadResponse(AlpideFile, "response1"); // Vbb=-3V + mAlpSimResp1 = loadResponse("ITSMFT/Calib/ALPIDEResponseVbbM3"); // Vbb=-3V mAlpSimResp1->computeCentreFromData(); mAlpSimResp1->print(); LOGP(info, "Response Centre {}", mAlpSimResp1->getRespCentreDep()); std::cout << "=====================\n"; LOGP(info, "APTS response"); - mAptSimResp1 = loadResponse(AptsFile, "response1"); // APTS + mAptSimResp1 = loadResponse("IT3/Calib/APTSResponse"); // APTS mAptSimResp1->computeCentreFromData(); mAptSimResp1->print(); LOGP(info, "Response Centre {}", mAptSimResp1->getRespCentreDep()); From 93cae7b66005fa79f1ecb5bd58e49d52e7cb33e8 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Thu, 12 Feb 2026 09:01:54 +0100 Subject: [PATCH 193/234] ITS3: split longerons, improving stepping speed (#15052) Signed-off-by: Felix Schlepper --- .../ITS3/base/include/ITS3Base/SpecsV2.h | 2 +- .../include/ITS3Simulation/ITS3Layer.h | 5 +- .../ITS3/simulation/src/ITS3Layer.cxx | 68 +++++++++---------- 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/Detectors/Upgrades/ITS3/base/include/ITS3Base/SpecsV2.h b/Detectors/Upgrades/ITS3/base/include/ITS3Base/SpecsV2.h index a7422c55e72b8..937fa8d2e982c 100644 --- a/Detectors/Upgrades/ITS3/base/include/ITS3Base/SpecsV2.h +++ b/Detectors/Upgrades/ITS3/base/include/ITS3Base/SpecsV2.h @@ -104,7 +104,7 @@ namespace carbonfoam // TODO: Waiting for the further information from WP5(Corrado) constexpr double HringLength{6.0 * mm}; // from blueprint constexpr double longeronsWidth{2.0 * mm}; // what is the height of the longerons? -constexpr double longeronsLength{segment::length - 2 * HringLength}; // 263mm from blueprint; overrriden to be consitent +constexpr double longeronsLength{segment::length - (2 * HringLength)}; // 263mm from blueprint; overrriden to be consitent constexpr double edgeBetwChipAndFoam{1.0 * mm}; // from blueprint but not used cause forms are already overlapping constexpr double gapBetwHringsLongerons{0.05 * mm}; // from blueprint constexpr std::array nHoles{11, 11, 11}; // how many holes for each layer? diff --git a/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/ITS3Layer.h b/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/ITS3Layer.h index fd9195f9ee228..f45a4469ae2b8 100644 --- a/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/ITS3Layer.h +++ b/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/ITS3Layer.h @@ -26,7 +26,7 @@ namespace o2::its3 { /// This class defines the geometry for the ITS3 IB layers. -class ITS3Layer +class ITS3Layer final { // The hierarchy will be the following: // ITS2 -> ITS3 @@ -76,7 +76,6 @@ class ITS3Layer void buildPartial(TGeoVolume* motherVolume, TGeoMatrix* mat = nullptr, BuildLevel level = BuildLevel::kAll, bool createMaterials = false); private: - bool mBuilt{false}; TGeoMedium* mSilicon{nullptr}; TGeoMedium* mAir{nullptr}; TGeoMedium* mCarbon{nullptr}; @@ -91,7 +90,7 @@ class ITS3Layer void createSegment(); void createChip(); void createCarbonForm(); - TGeoCompositeShape* getHringShape(TGeoTubeSeg* Hring); + TGeoCompositeShape* getHringShape(TGeoTubeSeg* Hring) const; void createLayerImpl(); uint8_t mNLayer{0}; // Layer number diff --git a/Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx b/Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx index e0be011096450..c0f8fdc19d03b 100644 --- a/Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx +++ b/Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx @@ -67,11 +67,11 @@ void ITS3Layer::createLayer(TGeoVolume* motherVolume) // Create one layer of ITS3 and attach it to the motherVolume. getMaterials(); createLayerImpl(); - mBuilt = true; if (motherVolume == nullptr) { return; } + // Add it to motherVolume auto* trans = new TGeoTranslation(0, 0, -constants::segment::lengthSensitive / 2.); motherVolume->AddNode(mLayer, 0, trans); @@ -122,8 +122,8 @@ void ITS3Layer::createTile() mTile->AddNode(mPixelArray, 0, phiRotPixelArray); // Biasing - double biasPhi1 = constants::pixelarray::width / mR * o2m::Rad2Deg + readoutPhi2; - double biasPhi2 = biasing::width / mR * o2m::Rad2Deg + biasPhi1; + double biasPhi1 = (constants::pixelarray::width / mR * o2m::Rad2Deg) + readoutPhi2; + double biasPhi2 = (biasing::width / mR * o2m::Rad2Deg) + biasPhi1; auto biasing = new TGeoTubeSeg(mRmin, mRmax, biasing::length / 2, biasPhi1, biasPhi2); auto biasingVol = new TGeoVolume(Form("biasing%d", mNLayer), biasing, mSilicon); biasingVol->SetLineColor(biasing::color); @@ -131,9 +131,9 @@ void ITS3Layer::createTile() mTile->AddNode(biasingVol, 0); // Power Switches are on the side right side of the pixel array and biasing. - auto zMovePowerSwitches = new TGeoTranslation(0, 0, +powerswitches::length / 2. + constants::pixelarray::length / 2.); + auto zMovePowerSwitches = new TGeoTranslation(0, 0, (+powerswitches::length / 2.) + (constants::pixelarray::length / 2.)); double powerPhi1 = readoutPhi2; - double powerPhi2 = powerswitches::width / mR * o2m::Rad2Deg + powerPhi1; + double powerPhi2 = (powerswitches::width / mR * o2m::Rad2Deg) + powerPhi1; auto powerSwitches = new TGeoTubeSeg(mRmin, mRmax, powerswitches::length / 2, powerPhi1, powerPhi2); auto powerSwitchesVol = new TGeoVolume(Form("powerswitches%d", mNLayer), powerSwitches, mSilicon); powerSwitchesVol->SetLineColor(powerswitches::color); @@ -166,7 +166,7 @@ void ITS3Layer::createRSU() // Lower Left auto zMoveLL1 = new TGeoTranslation(0, 0, constants::tile::length); auto zMoveLL2 = new TGeoTranslation(0, 0, constants::tile::length * 2.); - auto zMoveLLDB = new TGeoTranslation(0, 0, -databackbone::length / 2. - constants::pixelarray::length / 2.); + auto zMoveLLDB = new TGeoTranslation(0, 0, (-databackbone::length / 2.) - (constants::pixelarray::length / 2.)); // Lets attach the tiles to the QS. mRSU->AddNode(mTile, nCopyRSU++, nullptr); mRSU->AddNode(mTile, nCopyRSU++, zMoveLL1); @@ -175,9 +175,9 @@ void ITS3Layer::createRSU() // Lower Right auto zMoveLR0 = new TGeoTranslation(0, 0, +length / 2.); - auto zMoveLR1 = new TGeoTranslation(0, 0, constants::tile::length + length / 2.); - auto zMoveLR2 = new TGeoTranslation(0, 0, constants::tile::length * 2. + length / 2.); - auto zMoveLRDB = new TGeoTranslation(0, 0, -databackbone::length / 2. + length / 2. - constants::pixelarray::length / 2.); + auto zMoveLR1 = new TGeoTranslation(0, 0, constants::tile::length + (length / 2.)); + auto zMoveLR2 = new TGeoTranslation(0, 0, (constants::tile::length * 2.) + (length / 2.)); + auto zMoveLRDB = new TGeoTranslation(0, 0, (-databackbone::length / 2.) + (length / 2.) - (constants::pixelarray::length / 2.)); // Lets attach the tiles to the QS. mRSU->AddNode(mTile, nCopyRSU++, zMoveLR0); mRSU->AddNode(mTile, nCopyRSU++, zMoveLR1); @@ -192,7 +192,7 @@ void ITS3Layer::createRSU() // Upper Left auto zMoveUL1 = new TGeoCombiTrans(0, 0, constants::tile::length, rot); auto zMoveUL2 = new TGeoCombiTrans(0, 0, constants::tile::length * 2., rot); - auto zMoveULDB = new TGeoCombiTrans(0, 0, -databackbone::length / 2. - constants::pixelarray::length / 2., rot); + auto zMoveULDB = new TGeoCombiTrans(0, 0, (-databackbone::length / 2.) - (constants::pixelarray::length / 2.), rot); // Lets attach the tiles to the QS. mRSU->AddNode(mTile, nCopyRSU++, rot); mRSU->AddNode(mTile, nCopyRSU++, zMoveUL1); @@ -201,9 +201,9 @@ void ITS3Layer::createRSU() // Upper Right auto zMoveUR0 = new TGeoCombiTrans(0, 0, +length / 2., rot); - auto zMoveUR1 = new TGeoCombiTrans(0, 0, constants::tile::length + length / 2., rot); - auto zMoveUR2 = new TGeoCombiTrans(0, 0, constants::tile::length * 2. + length / 2., rot); - auto zMoveURDB = new TGeoCombiTrans(0, 0, -databackbone::length / 2. + length / 2. - constants::pixelarray::length / 2., rot); + auto zMoveUR1 = new TGeoCombiTrans(0, 0, constants::tile::length + (length / 2.), rot); + auto zMoveUR2 = new TGeoCombiTrans(0, 0, (constants::tile::length * 2.) + (length / 2.), rot); + auto zMoveURDB = new TGeoCombiTrans(0, 0, (-databackbone::length / 2.) + (length / 2.) - (constants::pixelarray::length / 2.), rot); // Lets attach the tiles to the QS. mRSU->AddNode(mTile, nCopyRSU++, zMoveUR0); mRSU->AddNode(mTile, nCopyRSU++, zMoveUR1); @@ -225,9 +225,9 @@ void ITS3Layer::createSegment() mSegment = new TGeoVolumeAssembly(its3TGeo::getITS3SegmentPattern(mNLayer)); mSegment->VisibleDaughters(); - for (size_t i{0}; i < nRSUs; ++i) { - auto zMove = new TGeoTranslation(0, 0, +i * constants::rsu::length + constants::rsu::databackbone::length + constants::pixelarray::length / 2.); - mSegment->AddNode(mRSU, i, zMove); + for (unsigned int i{0}; i < nRSUs; ++i) { + auto zMove = new TGeoTranslation(0, 0, (i * constants::rsu::length) + constants::rsu::databackbone::length + (constants::pixelarray::length / 2.)); + mSegment->AddNode(mRSU, (int)i, zMove); } // LEC @@ -242,7 +242,7 @@ void ITS3Layer::createSegment() mSegment->AddNode(lecVol, 0, zMoveLEC); // REC; reuses lecPhi1,2 - auto zMoveREC = new TGeoTranslation(0, 0, nRSUs * constants::rsu::length + rec::length / 2.); + auto zMoveREC = new TGeoTranslation(0, 0, (nRSUs * constants::rsu::length) + (rec::length / 2.)); auto rec = new TGeoTubeSeg(mRmin, mRmax, rec::length / 2., lecPhi1, lecPhi2); auto recVol = new TGeoVolume(Form("rec%d", mNLayer), rec, mSilicon); @@ -266,11 +266,11 @@ void ITS3Layer::createChip() auto phiOffset = constants::segment::width / mR * o2m::Rad2Deg; for (unsigned int i{0}; i < constants::nSegments[mNLayer]; ++i) { auto rot = new TGeoRotation(Form("its3PhiSegmentOffset_%d_%d", mNLayer, i), 0, 0, phiOffset * i); - mChip->AddNode(mSegment, i, rot); + mChip->AddNode(mSegment, (int)i, rot); } // Add metal stack positioned radially outward - auto zMoveMetal = new TGeoTranslation(0, 0, constants::metalstack::length / 2. - constants::segment::lec::length); + auto zMoveMetal = new TGeoTranslation(0, 0, (constants::metalstack::length / 2.) - constants::segment::lec::length); auto metal = new TGeoTubeSeg(mRmax, mRmax + constants::metalstack::thickness, constants::metalstack::length / 2., 0, constants::nSegments[mNLayer] * phiOffset); auto metalVol = new TGeoVolume(Form("metal%d", mNLayer), metal, mCopper); metalVol->SetLineColor(constants::metalstack::color); @@ -296,7 +296,7 @@ void ITS3Layer::createCarbonForm() dRadius = constants::carbonfoam::thicknessOuterFoam; // TODO: lack of carbon foam radius for layer 2, use 0.7 cm as a temporary value } double phiSta = edgeBetwChipAndFoam / (0.5 * constants::radii[mNLayer + 1] + constants::radii[mNLayer]) * o2m::Rad2Deg; - double phiEnd = (constants::nSegments[mNLayer] * constants::segment::width) / constants::radii[mNLayer] * o2m::Rad2Deg - phiSta; + double phiEnd = ((constants::nSegments[mNLayer] * constants::segment::width) / constants::radii[mNLayer] * o2m::Rad2Deg) - phiSta; double phiLongeronsCover = longeronsWidth / (0.5 * constants::radii[mNLayer + 1] + constants::radii[mNLayer]) * o2m::Rad2Deg; // H-rings foam @@ -308,35 +308,37 @@ void ITS3Layer::createCarbonForm() HringCVol->SetLineColor(color); auto HringAVol = new TGeoVolume(Form("hringA%d", mNLayer), HringAWithHoles, mCarbon); HringAVol->SetLineColor(color); - auto zMoveHringC = new TGeoTranslation(0, 0, -constants::segment::lec::length + HringLength / 2.); - auto zMoveHringA = new TGeoTranslation(0, 0, -constants::segment::lec::length + HringLength / 2. + constants::segment::length - HringLength); + auto zMoveHringC = new TGeoTranslation(0, 0, -constants::segment::lec::length + (HringLength / 2.)); + auto zMoveHringA = new TGeoTranslation(0, 0, -constants::segment::lec::length + (HringLength / 2.) + constants::segment::length - HringLength); // Longerons are made by same material + // added separately to make navigation faster [[maybe_unused]] auto longeronR = new TGeoTubeSeg(Form("longeronR%d", mNLayer), mRmax, mRmax + dRadius, longeronsLength / 2., phiSta, phiSta + phiLongeronsCover); [[maybe_unused]] auto longeronL = new TGeoTubeSeg(Form("longeronL%d", mNLayer), mRmax, mRmax + dRadius, longeronsLength / 2., phiEnd - phiLongeronsCover, phiEnd); - TString nameLongerons = Form("longeronR%d + longeronL%d", mNLayer, mNLayer); - auto longerons = new TGeoCompositeShape(nameLongerons); - auto longeronsVol = new TGeoVolume(Form("longerons%d", mNLayer), longerons, mCarbon); - longeronsVol->SetLineColor(color); - auto zMoveLongerons = new TGeoTranslation(0, 0, -constants::segment::lec::length + constants::segment::length / 2.); + auto longeronRVol = new TGeoVolume(Form("longeronR%d", mNLayer), longeronR, mCarbon); + longeronRVol->SetLineColor(color); + auto longeronLVol = new TGeoVolume(Form("longeronL%d", mNLayer), longeronL, mCarbon); + longeronLVol->SetLineColor(color); + auto zMoveLongerons = new TGeoTranslation(0, 0, -constants::segment::lec::length + (constants::segment::length / 2.)); mCarbonForm->AddNode(HringCVol, 0, zMoveHringC); mCarbonForm->AddNode(HringAVol, 0, zMoveHringA); - mCarbonForm->AddNode(longeronsVol, 0, zMoveLongerons); + mCarbonForm->AddNode(longeronRVol, 0, zMoveLongerons); + mCarbonForm->AddNode(longeronLVol, 0, zMoveLongerons); mCarbonForm->AddNode(mChip, 0); } -TGeoCompositeShape* ITS3Layer::getHringShape(TGeoTubeSeg* Hring) +TGeoCompositeShape* ITS3Layer::getHringShape(TGeoTubeSeg* Hring) const { // Function to dig holes in H-rings using namespace constants::carbonfoam; double stepPhiHoles = (Hring->GetPhi2() - Hring->GetPhi1()) / (nHoles[mNLayer]); - double phiHolesSta = Hring->GetPhi1() + stepPhiHoles / 2.; + double phiHolesSta = Hring->GetPhi1() + (stepPhiHoles / 2.); double radiusHring = 0.5 * (Hring->GetRmin() + Hring->GetRmax()); TGeoCompositeShape* HringWithHoles = nullptr; TString nameAllHoles = ""; for (int iHoles = 0; iHoles < nHoles[mNLayer]; iHoles++) { - double phiHole = phiHolesSta + stepPhiHoles * iHoles; + double phiHole = phiHolesSta + (stepPhiHoles * iHoles); TString nameHole = Form("hole_%d_%d", iHoles, mNLayer); [[maybe_unused]] auto hole = new TGeoTube(nameHole, 0, radiusHoles[mNLayer], 3 * Hring->GetDz()); // move hole to the hring radius @@ -376,9 +378,7 @@ void ITS3Layer::createLayerImpl() void ITS3Layer::buildPartial(TGeoVolume* motherVolume, TGeoMatrix* mat, BuildLevel level, bool createMaterials) { - if (!mBuilt) { - getMaterials(createMaterials); - } + getMaterials(createMaterials); switch (level) { case BuildLevel::kPixelArray: createPixelArray(); From f926fb83e768fb8b60656bc8e9ed668f8debb7c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ku=C4=8Dera?= <26327373+vkucera@users.noreply.github.com> Date: Thu, 12 Feb 2026 10:34:03 +0100 Subject: [PATCH 194/234] MUON: Delete unused files (#15027) --- .../Detectors/MUON/MCH/src/DsChannelGroup.cxx | 16 - .../SegContour/src/SegmentationSVGWriter.cxx | 117 --- .../Raw/Encoder/Payload/RefBufferCRUBare.cxx | 938 ------------------ .../Encoder/Payload/RefBufferCRUUserLogic.cxx | 67 -- .../Raw/Encoder/Payload/RefBufferGBTBare.cxx | 239 ----- .../Encoder/Payload/RefBufferGBTUserLogic.cxx | 34 - .../MUON/MID/Filtering/test/bench_Filter.cxx | 98 -- .../include/MIDWorkflow/DecodedDataDumpSpec.h | 30 - .../include/MIDWorkflow/RawAggregatorSpec.h | 30 - .../MID/Workflow/src/DecodedDataDumpSpec.cxx | 84 -- .../src/decoded-data-dump-workflow.cxx | 65 -- 11 files changed, 1718 deletions(-) delete mode 100644 DataFormats/Detectors/MUON/MCH/src/DsChannelGroup.cxx delete mode 100644 Detectors/MUON/MCH/Mapping/SegContour/src/SegmentationSVGWriter.cxx delete mode 100644 Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUBare.cxx delete mode 100644 Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUUserLogic.cxx delete mode 100644 Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTBare.cxx delete mode 100644 Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTUserLogic.cxx delete mode 100644 Detectors/MUON/MID/Filtering/test/bench_Filter.cxx delete mode 100644 Detectors/MUON/MID/Workflow/include/MIDWorkflow/DecodedDataDumpSpec.h delete mode 100644 Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawAggregatorSpec.h delete mode 100644 Detectors/MUON/MID/Workflow/src/DecodedDataDumpSpec.cxx delete mode 100644 Detectors/MUON/MID/Workflow/src/decoded-data-dump-workflow.cxx diff --git a/DataFormats/Detectors/MUON/MCH/src/DsChannelGroup.cxx b/DataFormats/Detectors/MUON/MCH/src/DsChannelGroup.cxx deleted file mode 100644 index bcf10d74c95ff..0000000000000 --- a/DataFormats/Detectors/MUON/MCH/src/DsChannelGroup.cxx +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "DataFormatsMCH/DsChannelGroup.h" - -std::string o2::mch::DsChannelId() const -{ -} diff --git a/Detectors/MUON/MCH/Mapping/SegContour/src/SegmentationSVGWriter.cxx b/Detectors/MUON/MCH/Mapping/SegContour/src/SegmentationSVGWriter.cxx deleted file mode 100644 index b614346f1a42a..0000000000000 --- a/Detectors/MUON/MCH/Mapping/SegContour/src/SegmentationSVGWriter.cxx +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// @author Laurent Aphecetche - -#include "MCHMappingSegContour/CathodeSegmentationSVGWriter.h" -#include "MCHMappingInterface/CathodeSegmentation.h" -#include "MCHMappingSegContour/CathodeSegmentationContours.h" -#include "MCHContour/SVGWriter.h" -#include - -using namespace o2::mch::contour; - -namespace o2 -{ -namespace mch -{ -namespace mapping -{ - -std::string svgCathodeSegmentationDefaultStyle() -{ - return R"( -.pads { - fill: #EEEEEE; - stroke-width: 0.025px; - stroke: #AAAAAA; -} -.padchannels { - font-size: 0.4px; - font-family: arial; - fill: blue; - text-anchor: middle; -} -.dualsampas { - fill:none; - stroke-width: 0.025px; - stroke: #333333; -} -.detectionelements { - fill:none; - stroke-width:0.025px; - stroke: #000000; -} -.testpoints { - fill:red; - stroke-width:0.025px; - stroke: black; - opacity: 0.5; -} -)"; -} - -void svgCathodeSegmentation(const CathodeSegmentation& seg, SVGWriter& w, bool showdes, bool showdualsampas, bool showpads, - bool showpadchannels) -{ - std::vector> dualSampaContours = getDualSampaContours(seg); - std::vector>> dualSampaPads = getPadPolygons(seg); - std::vector> dualSampaPadChannels = getPadChannels(seg); - - if (dualSampaPadChannels.size() != dualSampaPads.size()) { - throw std::runtime_error("gouze"); - } - - auto deContour = getEnvelop(seg); - auto box = getBBox(seg); - - if (showpads) { - w.svgGroupStart("pads"); - for (auto& dsp : dualSampaPads) { - for (auto& p : dsp) { - w.polygon(p); - } - } - w.svgGroupEnd(); - } - - if (showpadchannels) { - w.svgGroupStart("padchannels"); - for (auto i = 0; i < dualSampaPads.size(); ++i) { - auto& dsp = dualSampaPads[i]; - auto& dspch = dualSampaPadChannels[i]; - for (auto j = 0; j < dsp.size(); j++) { - auto bbox = getBBox(dsp[j]); - w.text(std::to_string(dspch[j]), bbox.xcenter(), - bbox.ymax() - 0.05 * bbox.height()); // SVG text y position is the bottom of the text - } - } - w.svgGroupEnd(); - } - - if (showdualsampas) { - w.svgGroupStart("dualsampas"); - for (auto& dsp : dualSampaContours) { - w.contour(dsp); - } - w.svgGroupEnd(); - } - - if (showdes) { - w.svgGroupStart("detectionelements"); - w.contour(deContour); - } -} - -} // namespace mapping -} // namespace mch -} // namespace o2 diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUBare.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUBare.cxx deleted file mode 100644 index 52e4581da1a71..0000000000000 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUBare.cxx +++ /dev/null @@ -1,938 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "RefBuffers.h" -#include -#include "MCHRawCommon/DataFormats.h" - -extern std::array REF_BUFFER_CRU_BARE_CHARGESUM; -template <> -gsl::span REF_BUFFER_CRU() -{ - return gsl::span(reinterpret_cast(&REF_BUFFER_CRU_BARE_CHARGESUM[0]), REF_BUFFER_CRU_BARE_CHARGESUM.size()); -} -std::array REF_BUFFER_CRU_BARE_CHARGESUM = { - // clang-format off -0x04, 0x40, 0x00, 0x00, 0x1B, 0x01, 0x00, 0x00, 0xB0, 0x12, 0xB0, 0x12, -0x00, 0x00, 0x0D, 0x10, 0x39, 0x30, 0x00, 0x00, 0x39, 0x30, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0x02, 0xA6, 0x02, -0x03, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA9, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAB, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA9, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA9, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA9, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA9, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAB, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA9, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAB, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA9, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAB, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA9, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA9, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAB, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA9, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA9, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAB, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAB, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA9, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAB, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAB, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA9, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAB, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA9, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xA8, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, -0x1B, 0x01, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x01, 0x0D, 0x10, -0x39, 0x30, 0x00, 0x00, 0x39, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xA6, 0x02, 0xA6, 0x02, 0x03, 0x08, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x04, 0x40, 0x00, 0x00, 0x1E, 0x01, 0x00, 0x00, 0x40, 0x0A, 0x40, 0x0A, -0x00, 0x00, 0x0F, 0x00, 0x39, 0x30, 0x00, 0x00, 0x39, 0x30, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0x02, 0xA6, 0x02, -0x03, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA6, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAE, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA6, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA6, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA6, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF3, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA6, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAE, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAE, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xF3, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA6, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA2, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA6, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, -0x1E, 0x01, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x01, 0x0F, 0x00, -0x39, 0x30, 0x00, 0x00, 0x39, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xA6, 0x02, 0xA6, 0x02, 0x03, 0x08, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x04, 0x40, 0x00, 0x00, 0x1B, 0x01, 0x00, 0x00, 0x10, 0x0D, 0x10, 0x0D, -0x07, 0x00, 0x0D, 0x10, 0x39, 0x30, 0x00, 0x00, 0x39, 0x30, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0x02, 0xA6, 0x02, -0x03, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAB, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAB, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA9, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA9, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAB, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA9, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, -0x1B, 0x01, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x07, 0x01, 0x0D, 0x10, -0x39, 0x30, 0x00, 0x00, 0x39, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xA6, 0x02, 0xA6, 0x02, 0x03, 0x08, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - - // clang-format on -}; diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUUserLogic.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUUserLogic.cxx deleted file mode 100644 index 3c3781460f4d1..0000000000000 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUUserLogic.cxx +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "RefBuffers.h" -#include -#include "MCHRawCommon/DataFormats.h" - -extern std::array REF_BUFFER_CRU_USERLOGIC_CHARGESUM; -template <> -gsl::span REF_BUFFER_CRU() -{ - return gsl::span(reinterpret_cast(&REF_BUFFER_CRU_USERLOGIC_CHARGESUM[0]), REF_BUFFER_CRU_USERLOGIC_CHARGESUM.size()); -} -std::array REF_BUFFER_CRU_USERLOGIC_CHARGESUM = { - // clang-format off -0x04, 0x40, 0x00, 0x00, 0x1E, 0x01, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, -0x0F, 0x00, 0x0F, 0x00, 0x39, 0x30, 0x00, 0x00, 0x39, 0x30, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0x02, 0xA6, 0x02, -0x03, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x13, 0x01, 0xF0, 0x40, 0x55, 0x55, 0xA1, 0x00, -0x03, 0x12, 0x00, 0xE3, 0x46, 0x00, 0xA0, 0x00, 0x01, 0x60, 0xD0, 0x00, -0x00, 0x58, 0xA2, 0x00, 0x04, 0x40, 0xBB, 0x11, 0x00, 0x01, 0xA0, 0x00, -0x18, 0x14, 0x02, 0x40, 0x90, 0x04, 0xA0, 0x00, 0x70, 0x6F, 0x04, 0x40, -0x00, 0x18, 0xA0, 0x00, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x00, -0xED, 0xDE, 0xED, 0xFE, 0xED, 0xDE, 0xED, 0xFE, 0x04, 0x40, 0x00, 0x00, -0x1E, 0x01, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x0F, 0x01, 0x0F, 0x00, -0x39, 0x30, 0x00, 0x00, 0x39, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xA6, 0x02, 0xA6, 0x02, 0x03, 0x08, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x04, 0x40, 0x00, 0x00, 0x1B, 0x01, 0x00, 0x00, 0xF0, 0x00, 0xF0, 0x00, -0x0F, 0x00, 0x0D, 0x10, 0x39, 0x30, 0x00, 0x00, 0x39, 0x30, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0x02, 0xA6, 0x02, -0x03, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x13, 0x01, 0xF0, 0x40, 0x55, 0x55, 0x81, 0x38, -0x1A, 0x12, 0x80, 0xE0, 0x46, 0x00, 0x80, 0x38, 0x01, 0x60, 0xA0, 0x00, -0x00, 0x4D, 0x82, 0x38, 0x04, 0x60, 0xB8, 0x11, 0x00, 0x01, 0x80, 0x38, -0x18, 0x50, 0x00, 0x80, 0x90, 0x04, 0x80, 0x38, 0x28, 0x6E, 0x04, 0x40, -0x00, 0x18, 0x80, 0x38, 0x1E, 0x00, 0x50, 0x21, 0x01, 0x38, 0x82, 0x38, -0x1B, 0x01, 0x10, 0x00, 0x06, 0x28, 0x80, 0x38, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x80, 0x38, 0xED, 0xDE, 0xED, 0xFE, 0xED, 0xDE, 0xED, 0xFE, -0x13, 0x01, 0xF0, 0x40, 0x55, 0x55, 0x01, 0x04, 0x03, 0x12, 0x40, 0xF6, -0x46, 0x00, 0x00, 0x04, 0x01, 0x60, 0x40, 0x1A, 0x00, 0x54, 0x02, 0x04, -0x04, 0xD0, 0xBD, 0x11, 0x00, 0x01, 0x00, 0x04, 0x18, 0xB8, 0x06, 0x00, -0x96, 0x04, 0x00, 0x04, 0x84, 0x6F, 0x04, 0x40, 0x00, 0x18, 0x00, 0x04, -0xB8, 0x01, 0xF0, 0x20, 0x01, 0x94, 0x03, 0x04, 0x1B, 0x01, 0x10, 0x00, -0x06, 0xC2, 0x01, 0x04, 0x00, 0x00, 0x48, 0x00, 0xE9, 0x1B, 0x01, 0x04, -0x00, 0x04, 0x80, 0x01, 0x73, 0x00, 0x00, 0x04, 0x48, 0x12, 0x50, 0xEA, -0x46, 0x00, 0x00, 0x04, 0x01, 0x60, 0x40, 0x1A, 0x00, 0x00, 0x00, 0x04, -0x04, 0x40, 0x00, 0x00, 0x1B, 0x01, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, -0x0F, 0x01, 0x0D, 0x10, 0x39, 0x30, 0x00, 0x00, 0x39, 0x30, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0x02, 0xA6, 0x02, -0x03, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00 - // clang-format on -}; diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTBare.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTBare.cxx deleted file mode 100644 index 89b1602cb0489..0000000000000 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTBare.cxx +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "RefBuffers.h" -#include -#include "MCHRawCommon/DataFormats.h" - -extern std::array REF_BUFFER_GBT_BARE_CHARGESUM; -template <> -gsl::span REF_BUFFER_GBT() -{ - return gsl::span(reinterpret_cast(&REF_BUFFER_GBT_BARE_CHARGESUM[0]), REF_BUFFER_GBT_BARE_CHARGESUM.size()); -} -std::array REF_BUFFER_GBT_BARE_CHARGESUM = { - // clang-format off -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xBC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xBC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x69, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xEB, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xBD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAB, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x2A, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x2A, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x3C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x7D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xEB, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x3C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x3C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xAB, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x2A, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6A, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xA8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0xE8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xE8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x3E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x2A, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x2A, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x28, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, -0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00 - // clang-format on -}; diff --git a/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTUserLogic.cxx b/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTUserLogic.cxx deleted file mode 100644 index 9487037328ad2..0000000000000 --- a/Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTUserLogic.cxx +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "RefBuffers.h" -#include -#include "MCHRawCommon/DataFormats.h" - -extern std::array REF_BUFFER_GBT_USERLOGIC_CHARGESUM; -template <> -gsl::span REF_BUFFER_GBT() -{ - return gsl::span(reinterpret_cast(&REF_BUFFER_GBT_USERLOGIC_CHARGESUM[0]), REF_BUFFER_GBT_USERLOGIC_CHARGESUM.size()); -} -std::array REF_BUFFER_GBT_USERLOGIC_CHARGESUM = { - // clang-format off -0x13, 0x01, 0xF0, 0x40, 0x55, 0x55, 0x01, 0x58, 0x0C, 0x12, 0x00, 0xA0, -0x50, 0x03, 0x00, 0x58, 0x01, 0x30, 0xA0, 0x00, 0x00, 0x5B, 0x02, 0x58, -0x04, 0xC0, 0x2F, 0xD4, 0x00, 0x01, 0x00, 0x58, 0x0C, 0x80, 0x02, 0x00, -0x00, 0x00, 0x00, 0x58, 0x13, 0x01, 0xF0, 0x40, 0x55, 0x55, 0x61, 0x58, -0x19, 0x12, 0x60, 0xAD, 0x50, 0x03, 0x60, 0x58, 0x01, 0x30, 0xD0, 0x00, -0x00, 0x09, 0x62, 0x58, 0x04, 0x5C, 0x28, 0xD4, 0x00, 0x01, 0x60, 0x58, -0x0C, 0x14, 0x02, 0x40, 0x82, 0x04, 0x60, 0x58, 0xF7, 0x0B, 0x35, 0x40, -0x00, 0x0C, 0x60, 0x58, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x58 - - // clang-format on -}; diff --git a/Detectors/MUON/MID/Filtering/test/bench_Filter.cxx b/Detectors/MUON/MID/Filtering/test/bench_Filter.cxx deleted file mode 100644 index a54ea9c1733a8..0000000000000 --- a/Detectors/MUON/MID/Filtering/test/bench_Filter.cxx +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file MID/Tracking/test/bench_Tracker.cxx -/// \brief Benchmark tracker device for MID -/// \author Diego Stocco -/// \date 17 March 2018 - -#include "benchmark/benchmark.h" -#include -#include "DataFormatsMID/Cluster.h" -#include "DataFormatsMID/Track.h" -#include "MIDBase/HitFinder.h" -#include "MIDBase/Mapping.h" -#include "MIDBase/MpArea.h" -#include "MIDTestingSimTools/TrackGenerator.h" -#include "MIDTracking/Tracker.h" - -std::vector generateTestData(int nTracks, o2::mid::TrackGenerator& trackGen, - const o2::mid::HitFinder& hitFinder, const o2::mid::Mapping& mapping) -{ - o2::mid::Mapping::MpStripIndex stripIndex; - o2::mid::MpArea area; - std::vector clusters; - o2::mid::Cluster cl; - std::vector tracks = trackGen.generate(nTracks); - for (auto& track : tracks) { - for (int ich = 0; ich < 4; ++ich) { - auto hits = hitFinder.getLocalPositions(track, ich); - bool isFired = false; - for (auto& hit : hits) { - int deId = hit.deId; - float xPos = hit.xCoor; - float yPos = hit.yCoor; - stripIndex = mapping.stripByPosition(xPos, yPos, 0, deId, false); - if (!stripIndex.isValid()) { - continue; - } - cl.deId = deId; - area = mapping.stripByLocation(stripIndex.strip, 0, stripIndex.line, stripIndex.column, deId); - cl.yCoor = area.getCenterY(); - cl.yErr = area.getHalfSizeY() / std::sqrt(3.); - stripIndex = mapping.stripByPosition(xPos, yPos, 1, deId, false); - area = mapping.stripByLocation(stripIndex.strip, 1, stripIndex.line, stripIndex.column, deId); - cl.xCoor = area.getCenterX(); - cl.xErr = area.getHalfSizeX() / std::sqrt(3.); - clusters.push_back(cl); - } // loop on fired pos - } // loop on chambers - } // loop on tracks - return clusters; -} - -static void BM_TRACKER(benchmark::State& state) -{ - o2::mid::GeometryTransformer geoTrans = o2::mid::createDefaultTransformer(); - o2::mid::TrackGenerator trackGen; - o2::mid::HitFinder hitFinder(geoTrans); - o2::mid::Mapping mapping; - o2::mid::Tracker tracker(geoTrans); - - int nTracksPerEvent = state.range(0); - tracker.init((state.range(1) == 1)); - double num{0}; - - std::vector inputData; - - for (auto _ : state) { - state.PauseTiming(); - inputData = generateTestData(nTracksPerEvent, trackGen, hitFinder, mapping); - state.ResumeTiming(); - tracker.process(inputData); - ++num; - } - - state.counters["num"] = benchmark::Counter(num, benchmark::Counter::kIsRate); -} - -static void CustomArguments(benchmark::internal::Benchmark* bench) -{ - for (int itrack = 1; itrack <= 8; ++itrack) { - for (int imethod = 0; imethod < 2; ++imethod) { - bench->Args({itrack, imethod}); - } - } -} - -BENCHMARK(BM_TRACKER)->Apply(CustomArguments)->Unit(benchmark::kNanosecond); - -BENCHMARK_MAIN(); diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/DecodedDataDumpSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/DecodedDataDumpSpec.h deleted file mode 100644 index 4d104aacac15c..0000000000000 --- a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/DecodedDataDumpSpec.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file MIDWorkflow/RawDumpSpec.h -/// \brief Device to dump decoded raw data -/// \author Diego Stocco -/// \date 17 February 2022 - -#ifndef O2_MID_RAWDUMPSPEC_H -#define O2_MID_RAWDUMPSPEC_H - -#include "Framework/DataProcessorSpec.h" - -namespace o2 -{ -namespace mid -{ -framework::DataProcessorSpec getRawDumpSpec(); -} // namespace mid -} // namespace o2 - -#endif // O2_MID_RAWDUMPSPEC_H diff --git a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawAggregatorSpec.h b/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawAggregatorSpec.h deleted file mode 100644 index b5a6b33530c8f..0000000000000 --- a/Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawAggregatorSpec.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file MIDWorkflow/RawAggregatorSpec.h -/// \brief Data processor spec for MID raw data aggregator devices -/// \author Diego Stocco -/// \date 26 February 2020 - -#ifndef O2_MID_RAWAGGREGATORSPEC_H -#define O2_MID_RAWAGGREGATORSPEC_H - -#include "Framework/DataProcessorSpec.h" - -namespace o2 -{ -namespace mid -{ -framework::DataProcessorSpec getRawAggregatorSpec(); -} // namespace mid -} // namespace o2 - -#endif //O2_MID_RAWAGGREGATORSPEC_H diff --git a/Detectors/MUON/MID/Workflow/src/DecodedDataDumpSpec.cxx b/Detectors/MUON/MID/Workflow/src/DecodedDataDumpSpec.cxx deleted file mode 100644 index 77d05a8b3374f..0000000000000 --- a/Detectors/MUON/MID/Workflow/src/DecodedDataDumpSpec.cxx +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file MID/Workflow/src/RawDumpSpec.cxx -/// \brief Device to dump decoded raw data -/// \author Diego Stocco -/// \date 17 February 2022 - -#include "MIDWorkflow/RawDumpSpec.h" - -#include -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "Framework/Logger.h" -#include "Framework/Task.h" -#include "fmt/format.h" -#include "DataFormatsMID/ROBoard.h" -#include "DataFormatsMID/ROFRecord.h" - -namespace o2 -{ -namespace mid -{ - -class RawDumpDeviceDPL -{ - public: - void init(o2::framework::InitContext& ic) - { - auto outFilename = ic.options().get("mid-dump-outfile"); - - if (!outFilename.empty()) { - mOutFile.open(outFilename.c_str()); - } - } - - void - run(o2::framework::ProcessingContext& pc) - { - - auto data = pc.inputs().get>("mid_decoded"); - auto dataROFs = pc.inputs().get>("mid_decoded_rof"); - std::stringstream ss; - for (auto& rof : dataROFs) { - ss << fmt::format("BCid: 0x{:x} Orbit: 0x{:x} EvtType: {:d}", rof.interactionRecord.bc, rof.interactionRecord.orbit, static_cast(rof.eventType)) << std::endl; - for (auto colIt = data.begin() + rof.firstEntry, end = data.begin() + rof.getEndIndex(); colIt != end; ++colIt) { - ss << *colIt << std::endl; - } - } - if (mOutFile.is_open()) { - mOutFile << ss.str(); - } else { - LOG(info) << ss.str(); - } - } - - private: - std::ofstream mOutFile; /// Output file -}; - -framework::DataProcessorSpec getRawDumpSpec() -{ - std::vector inputSpecs{ - o2::framework::InputSpec{"mid_decoded", header::gDataOriginMID, "DECODED", 0, o2::framework::Lifetime::Timeframe}, - o2::framework::InputSpec{"mid_decoded_rof", header::gDataOriginMID, "DECODEDROF", 0, o2::framework::Lifetime::Timeframe}}; - - return o2::framework::DataProcessorSpec{ - "MIDRawDataDumper", - {inputSpecs}, - {}, - o2::framework::AlgorithmSpec{o2::framework::adaptFromTask()}, - o2::framework::Options{{"mid-dump-outfile", o2::framework::VariantType::String, "", {"Dump output to file"}}}}; -} - -} // namespace mid -} // namespace o2 diff --git a/Detectors/MUON/MID/Workflow/src/decoded-data-dump-workflow.cxx b/Detectors/MUON/MID/Workflow/src/decoded-data-dump-workflow.cxx deleted file mode 100644 index 036b63bc75338..0000000000000 --- a/Detectors/MUON/MID/Workflow/src/decoded-data-dump-workflow.cxx +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file MID/Workflow/src/raw-dump-workflow.cxx -/// \brief MID raw dump workflow -/// \author Diego Stocco -/// \date 17 February 2022 - -#include -#include -#include "Framework/Variant.h" -#include "Framework/ConfigParamSpec.h" -#include "MIDRaw/CrateMasks.h" -#include "MIDRaw/ElectronicsDelay.h" -#include "MIDRaw/FEEIdConfig.h" -#include "MIDWorkflow/RawDumpSpec.h" -#include "MIDWorkflow/RawDecoderSpec.h" - -using namespace o2::framework; - -// add workflow options, note that customization needs to be declared before -// including Framework/runDataProcessing -void customize(std::vector& workflowOptions) -{ - std::vector - options{ - {"feeId-config-file", VariantType::String, "", {"Filename with crate FEE ID correspondence"}}, - {"crate-masks-file", VariantType::String, "", {"Filename with crate masks"}}, - {"electronics-delay-file", VariantType::String, "", {"Filename with electronics delay"}}}; - workflowOptions.insert(workflowOptions.end(), options.begin(), options.end()); -} - -#include "Framework/runDataProcessing.h" - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - auto feeIdConfigFilename = cfgc.options().get("feeId-config-file"); - o2::mid::FEEIdConfig feeIdConfig; - if (!feeIdConfigFilename.empty()) { - feeIdConfig = o2::mid::FEEIdConfig(feeIdConfigFilename.c_str()); - } - auto crateMasksFilename = cfgc.options().get("crate-masks-file"); - o2::mid::CrateMasks crateMasks; - if (!crateMasksFilename.empty()) { - crateMasks = o2::mid::CrateMasks(crateMasksFilename.c_str()); - } - auto electronicsDelayFilename = cfgc.options().get("electronics-delay-file"); - o2::mid::ElectronicsDelay electronicsDelay; - if (!electronicsDelayFilename.empty()) { - electronicsDelay = o2::mid::readElectronicsDelay(electronicsDelayFilename.c_str()); - } - - WorkflowSpec specs; - specs.emplace_back(o2::mid::getRawDecoderSpec(true, feeIdConfig, crateMasks, electronicsDelay, false)); - specs.emplace_back(o2::mid::getRawDumpSpec()); - return specs; -} From 87fa1f6c3befc55da9d538d04dab3b2811793c91 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Thu, 12 Feb 2026 11:08:37 +0100 Subject: [PATCH 195/234] ITSMFT: scaffolding for staggered clusterization (#15004) * ITS staggered clusterization Signed-off-by: Felix Schlepper * Simplify getMaxBCDiffToSquashBias function --------- Signed-off-by: Felix Schlepper --- .../src/StrangenessTrackingSpec.cxx | 2 - Detectors/ITSMFT/ITS/workflow/CMakeLists.txt | 2 - .../include/ITSWorkflow/ClustererSpec.h | 65 ---- .../ITS/workflow/src/ClusterWriterSpec.cxx | 72 ---- .../workflow/src/ClusterWriterWorkflow.cxx | 4 +- .../ITSMFT/ITS/workflow/src/ClustererSpec.cxx | 218 ------------ .../ITSMFT/ITS/workflow/src/RecoWorkflow.cxx | 8 +- Detectors/ITSMFT/MFT/workflow/CMakeLists.txt | 2 - .../include/MFTWorkflow/ClusterWriterSpec.h | 31 -- .../MFT/workflow/src/ClusterWriterSpec.cxx | 72 ---- .../ITSMFT/MFT/workflow/src/ClustererSpec.cxx | 212 ------------ .../ITSMFT/MFT/workflow/src/RecoWorkflow.cxx | 8 +- .../src/mft-cluster-writer-workflow.cxx | 4 +- .../include/ITSMFTReconstruction/Clusterer.h | 14 +- .../ITSMFTReconstruction/ClustererParam.h | 22 +- .../ITSMFTReconstruction/DigitPixelReader.h | 3 +- .../common/reconstruction/src/Clusterer.cxx | 36 +- .../reconstruction/src/DigitPixelReader.cxx | 11 + .../ITSMFT/common/workflow/CMakeLists.txt | 2 + .../ITSMFTWorkflow/ClusterReaderSpec.h | 52 ++- .../ITSMFTWorkflow}/ClusterWriterSpec.h | 16 +- .../include/ITSMFTWorkflow}/ClustererSpec.h | 28 +- .../common/workflow/src/ClusterReaderSpec.cxx | 166 +++++---- .../common/workflow/src/ClusterWriterSpec.cxx | 107 ++++++ .../common/workflow/src/ClustererSpec.cxx | 325 ++++++++++++++++++ .../ITS3/workflow/src/RecoWorkflow.cxx | 4 +- 26 files changed, 648 insertions(+), 838 deletions(-) delete mode 100644 Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClustererSpec.h delete mode 100644 Detectors/ITSMFT/ITS/workflow/src/ClusterWriterSpec.cxx delete mode 100644 Detectors/ITSMFT/ITS/workflow/src/ClustererSpec.cxx delete mode 100644 Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClusterWriterSpec.h delete mode 100644 Detectors/ITSMFT/MFT/workflow/src/ClusterWriterSpec.cxx delete mode 100644 Detectors/ITSMFT/MFT/workflow/src/ClustererSpec.cxx rename Detectors/ITSMFT/{ITS/workflow/include/ITSWorkflow => common/workflow/include/ITSMFTWorkflow}/ClusterWriterSpec.h (73%) rename Detectors/ITSMFT/{MFT/workflow/include/MFTWorkflow => common/workflow/include/ITSMFTWorkflow}/ClustererSpec.h (64%) create mode 100644 Detectors/ITSMFT/common/workflow/src/ClusterWriterSpec.cxx create mode 100644 Detectors/ITSMFT/common/workflow/src/ClustererSpec.cxx diff --git a/Detectors/GlobalTrackingWorkflow/src/StrangenessTrackingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/StrangenessTrackingSpec.cxx index 849964aeaf871..e313940b0a91e 100644 --- a/Detectors/GlobalTrackingWorkflow/src/StrangenessTrackingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/StrangenessTrackingSpec.cxx @@ -17,10 +17,8 @@ #include "DataFormatsGlobalTracking/RecoContainer.h" #include "StrangenessTracking/StrangenessTrackingConfigParam.h" #include "GlobalTrackingWorkflow/StrangenessTrackingSpec.h" -#include "ITSWorkflow/ClusterWriterSpec.h" #include "ITSWorkflow/TrackerSpec.h" #include "ITSWorkflow/TrackReaderSpec.h" -#include "ITSMFTWorkflow/ClusterReaderSpec.h" #include "Framework/CCDBParamSpec.h" #include "DataFormatsParameters/GRPObject.h" diff --git a/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt b/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt index f0d50e59493d4..10e16e49d92b5 100644 --- a/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt @@ -13,8 +13,6 @@ o2_add_library(ITSWorkflow TARGETVARNAME targetName SOURCES src/RecoWorkflow.cxx src/ClusterWriterWorkflow.cxx - src/ClustererSpec.cxx - src/ClusterWriterSpec.cxx src/TrackerSpec.cxx src/TrackWriterSpec.cxx src/TrackReaderSpec.cxx diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClustererSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClustererSpec.h deleted file mode 100644 index c5038c87fa467..0000000000000 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClustererSpec.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file ClustererSpec.h - -#ifndef O2_ITS_CLUSTERERDPL -#define O2_ITS_CLUSTERERDPL - -#include -#include "DetectorsBase/GRPGeomHelper.h" -#include "ITSMFTReconstruction/Clusterer.h" -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" - -using namespace o2::framework; - -namespace o2 -{ - -namespace itsmft -{ -class Clusterer; -} - -namespace its -{ - -class ClustererDPL : public Task -{ - public: - ClustererDPL(std::shared_ptr gr, bool useMC) : mGGCCDBRequest(gr), mUseMC(useMC) {} - ~ClustererDPL() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final; - void endOfStream(o2::framework::EndOfStreamContext& ec) final; - - private: - void updateTimeDependentParams(ProcessingContext& pc); - - int mState = 0; - bool mUseMC = true; - bool mUseClusterDictionary = true; - int mNThreads = 1; - std::unique_ptr mFile = nullptr; - std::unique_ptr mClusterer = nullptr; - std::shared_ptr mGGCCDBRequest; -}; - -/// create a processor spec -/// run ITS cluster finder -framework::DataProcessorSpec getClustererSpec(bool useMC); - -} // namespace its -} // namespace o2 - -#endif /* O2_ITS_CLUSTERERDPL */ diff --git a/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterSpec.cxx deleted file mode 100644 index 4dffbaf88893c..0000000000000 --- a/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterSpec.cxx +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file ClusterWriterSpec.cxx - -#include - -#include "ITSWorkflow/ClusterWriterSpec.h" -#include "DPLUtils/MakeRootTreeWriterSpec.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace its -{ - -template -using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition; -using CompClusType = std::vector; -using PatternsType = std::vector; -using ROFrameRType = std::vector; -using LabelsType = o2::dataformats::MCTruthContainer; -using ROFRecLblT = std::vector; -using namespace o2::header; - -DataProcessorSpec getClusterWriterSpec(bool useMC) -{ - // Spectators for logging - // this is only to restore the original behavior - auto compClustersSize = std::make_shared(0); - auto compClustersSizeGetter = [compClustersSize](CompClusType const& compClusters) { - *compClustersSize = compClusters.size(); - }; - auto logger = [compClustersSize](std::vector const& rofs) { - LOG(info) << "ITSClusterWriter pulled " << *compClustersSize << " clusters, in " << rofs.size() << " RO frames"; - }; - return MakeRootTreeWriterSpec("its-cluster-writer", - "o2clus_its.root", - MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with ITS clusters"}, - BranchDefinition{InputSpec{"compclus", "ITS", "COMPCLUSTERS", 0}, - "ITSClusterComp", - compClustersSizeGetter}, - BranchDefinition{InputSpec{"patterns", "ITS", "PATTERNS", 0}, - "ITSClusterPatt"}, - BranchDefinition{InputSpec{"ROframes", "ITS", "CLUSTERSROF", 0}, - "ITSClustersROF", - logger}, - BranchDefinition{InputSpec{"labels", "ITS", "CLUSTERSMCTR", 0}, - "ITSClusterMCTruth", - (useMC ? 1 : 0), // one branch if mc labels enabled - ""}, - BranchDefinition{InputSpec{"MC2ROframes", "ITS", "CLUSTERSMC2ROF", 0}, - "ITSClustersMC2ROF", - (useMC ? 1 : 0), // one branch if mc labels enabled - ""})(); -} - -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterWorkflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterWorkflow.cxx index ca5db7acd63e1..aba468b3e9460 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterWorkflow.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/ClusterWriterWorkflow.cxx @@ -12,7 +12,7 @@ /// @file ClusterWriterWorkflow.cxx #include "ITSWorkflow/ClusterWriterWorkflow.h" -#include "ITSWorkflow/ClusterWriterSpec.h" +#include "ITSMFTWorkflow/ClusterWriterSpec.h" namespace o2 { @@ -26,7 +26,7 @@ framework::WorkflowSpec getWorkflow(bool useMC) { framework::WorkflowSpec specs; - specs.emplace_back(o2::its::getClusterWriterSpec(useMC)); + specs.emplace_back(o2::itsmft::getITSClusterWriterSpec(useMC)); return specs; } diff --git a/Detectors/ITSMFT/ITS/workflow/src/ClustererSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/ClustererSpec.cxx deleted file mode 100644 index d58e4f5d915c1..0000000000000 --- a/Detectors/ITSMFT/ITS/workflow/src/ClustererSpec.cxx +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file ClustererSpec.cxx - -#include - -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/CCDBParamSpec.h" -#include "ITSWorkflow/ClustererSpec.h" -#include "DataFormatsITSMFT/Digit.h" -#include "ITSMFTReconstruction/ChipMappingITS.h" -#include "ITSMFTReconstruction/ClustererParam.h" -#include "DataFormatsITSMFT/TopologyDictionary.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/ConstMCTruthContainer.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "DataFormatsParameters/GRPObject.h" -#include "ITSMFTReconstruction/DigitPixelReader.h" -#include "ITSMFTBase/DPLAlpideParam.h" -#include "CommonConstants/LHCConstants.h" -#include "DetectorsCommonDataFormats/DetectorNameConf.h" - -using namespace o2::framework; -using namespace o2::itsmft; - -namespace o2 -{ -namespace its -{ - -void ClustererDPL::init(InitContext& ic) -{ - mClusterer = std::make_unique(); - mClusterer->setNChips(o2::itsmft::ChipMappingITS::getNChips()); - mUseClusterDictionary = !ic.options().get("ignore-cluster-dictionary"); - o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); - mNThreads = std::max(1, ic.options().get("nthreads")); - LOGP(info, "Initialising ITSClusterer with {} threads", mNThreads); - mState = 1; -} - -void ClustererDPL::run(ProcessingContext& pc) -{ - updateTimeDependentParams(pc); - auto digits = pc.inputs().get>("digits"); - auto rofs = pc.inputs().get>("ROframes"); - - gsl::span mc2rofs; - gsl::span labelbuffer; - if (mUseMC) { - labelbuffer = pc.inputs().get>("labels"); - mc2rofs = pc.inputs().get>("MC2ROframes"); - } - o2::dataformats::ConstMCTruthContainerView labels(labelbuffer); - - LOG(info) << "ITSClusterer pulled " << digits.size() << " digits, in " - << rofs.size() << " RO frames"; - LOG(info) << "ITSClusterer pulled " << labels.getNElements() << " labels "; - - o2::itsmft::DigitPixelReader reader; - reader.setSquashingDepth(mClusterer->getMaxROFDepthToSquash()); - reader.setSquashingDist(mClusterer->getMaxRowColDiffToMask()); // Sharing same parameter/logic with masking - reader.setMaxBCSeparationToSquash(mClusterer->getMaxBCSeparationToSquash()); - reader.setDigits(digits); - reader.setROFRecords(rofs); - if (mUseMC) { - reader.setMC2ROFRecords(mc2rofs); - reader.setDigitsMCTruth(labels.getIndexedSize() > 0 ? &labels : nullptr); - } - reader.init(); - auto orig = o2::header::gDataOriginITS; - std::vector clusCompVec; - std::vector clusROFVec; - std::vector clusPattVec; - - std::unique_ptr> clusterLabels; - if (mUseMC) { - clusterLabels = std::make_unique>(); - } - mClusterer->process(mNThreads, reader, &clusCompVec, &clusPattVec, &clusROFVec, clusterLabels.get()); - pc.outputs().snapshot(Output{orig, "COMPCLUSTERS", 0}, clusCompVec); - pc.outputs().snapshot(Output{orig, "CLUSTERSROF", 0}, clusROFVec); - pc.outputs().snapshot(Output{orig, "PATTERNS", 0}, clusPattVec); - - if (mUseMC) { - pc.outputs().snapshot(Output{orig, "CLUSTERSMCTR", 0}, *clusterLabels.get()); // at the moment requires snapshot - std::vector clusterMC2ROframes(mc2rofs.size()); - for (int i = mc2rofs.size(); i--;) { - clusterMC2ROframes[i] = mc2rofs[i]; // Simply, replicate it from digits ? - } - pc.outputs().snapshot(Output{orig, "CLUSTERSMC2ROF", 0}, clusterMC2ROframes); - } - - // TODO: in principle, after masking "overflow" pixels the MC2ROFRecord maxROF supposed to change, nominally to minROF - // -> consider recalculationg maxROF - LOG(info) << "ITSClusterer pushed " << clusCompVec.size() << " clusters, in " << clusROFVec.size() << " RO frames"; -} - -///_______________________________________ -void ClustererDPL::updateTimeDependentParams(ProcessingContext& pc) -{ - static bool initOnceDone = false; - o2::base::GRPGeomHelper::instance().checkUpdates(pc); - if (!initOnceDone) { // this params need to be queried only once - initOnceDone = true; - pc.inputs().get("cldict"); // just to trigger the finaliseCCDB - pc.inputs().get*>("alppar"); - pc.inputs().get*>("cluspar"); - mClusterer->setContinuousReadOut(o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::ITS)); - // settings for the fired pixel overflow masking - const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); - const auto& clParams = o2::itsmft::ClustererParam::Instance(); - mClusterer->setDropHugeClusters(clParams.dropHugeClusters); - if (clParams.maxBCDiffToMaskBias > 0 && clParams.maxBCDiffToSquashBias > 0) { - LOGP(fatal, "maxBCDiffToMaskBias = {} and maxBCDiffToSquashBias = {} cannot be set at the same time. Either set masking or squashing with a BCDiff > 0", clParams.maxBCDiffToMaskBias, clParams.maxBCDiffToSquashBias); - } - auto nbc = clParams.maxBCDiffToMaskBias; - nbc += mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); - mClusterer->setMaxBCSeparationToMask(nbc); - mClusterer->setMaxRowColDiffToMask(clParams.maxRowColDiffToMask); - // Squasher - int rofBC = mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); // ROF length in BC - mClusterer->setMaxBCSeparationToSquash(rofBC + clParams.maxBCDiffToSquashBias); - int nROFsToSquash = 0; // squashing disabled if no reset due to maxSOTMUS>0. - if (clParams.maxSOTMUS > 0 && rofBC > 0) { - nROFsToSquash = 2 + int(clParams.maxSOTMUS / (rofBC * o2::constants::lhc::LHCBunchSpacingMUS)); // use squashing - } - mClusterer->setMaxROFDepthToSquash(clParams.maxBCDiffToSquashBias > 0 ? nROFsToSquash : 0); - mClusterer->print(); - } - // we may have other params which need to be queried regularly -} - -///_______________________________________ -void ClustererDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) -{ - if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { - return; - } - if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) { - LOG(info) << "cluster dictionary updated" << (!mUseClusterDictionary ? " but its using is disabled" : ""); - if (mUseClusterDictionary) { - mClusterer->setDictionary((const o2::itsmft::TopologyDictionary*)obj); - } - return; - } - // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level - if (matcher == ConcreteDataMatcher("ITS", "ALPIDEPARAM", 0)) { - LOG(info) << "Alpide param updated"; - const auto& par = o2::itsmft::DPLAlpideParam::Instance(); - par.printKeyValues(); - return; - } - if (matcher == ConcreteDataMatcher("ITS", "CLUSPARAM", 0)) { - LOG(info) << "Cluster param updated"; - const auto& par = o2::itsmft::ClustererParam::Instance(); - par.printKeyValues(); - return; - } -} - -DataProcessorSpec getClustererSpec(bool useMC) -{ - std::vector inputs; - inputs.emplace_back("digits", "ITS", "DIGITS", 0, Lifetime::Timeframe); - inputs.emplace_back("ROframes", "ITS", "DIGITSROF", 0, Lifetime::Timeframe); - inputs.emplace_back("cldict", "ITS", "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec("ITS/Calib/ClusterDictionary")); - inputs.emplace_back("cluspar", "ITS", "CLUSPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/ClustererParam")); - inputs.emplace_back("alppar", "ITS", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/AlpideParam")); - auto ggRequest = std::make_shared(false, // orbitResetTime - true, // GRPECS=true - false, // GRPLHCIF - false, // GRPMagField - false, // askMatLUT - o2::base::GRPGeomRequest::None, // geometry - inputs, - true); - std::vector outputs; - outputs.emplace_back("ITS", "COMPCLUSTERS", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "PATTERNS", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "CLUSTERSROF", 0, Lifetime::Timeframe); - - if (useMC) { - inputs.emplace_back("labels", "ITS", "DIGITSMCTR", 0, Lifetime::Timeframe); - inputs.emplace_back("MC2ROframes", "ITS", "DIGITSMC2ROF", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "CLUSTERSMCTR", 0, Lifetime::Timeframe); - outputs.emplace_back("ITS", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe); - } - - return DataProcessorSpec{ - "its-clusterer", - inputs, - outputs, - AlgorithmSpec{adaptFromTask(ggRequest, useMC)}, - Options{ - {"ignore-cluster-dictionary", VariantType::Bool, false, {"do not use cluster dictionary, always store explicit patterns"}}, - {"nthreads", VariantType::Int, 1, {"Number of clustering threads"}}}}; -} - -///_______________________________________ -void ClustererDPL::endOfStream(o2::framework::EndOfStreamContext& ec) -{ - mClusterer->print(); -} - -} // namespace its -} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx index 60e28556716f2..9f8cb6c83ef99 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx @@ -12,8 +12,8 @@ /// @file RecoWorkflow.cxx #include "ITSWorkflow/RecoWorkflow.h" -#include "ITSWorkflow/ClustererSpec.h" -#include "ITSWorkflow/ClusterWriterSpec.h" +#include "ITSMFTWorkflow/ClustererSpec.h" +#include "ITSMFTWorkflow/ClusterWriterSpec.h" #include "ITSWorkflow/TrackerSpec.h" #include "ITSWorkflow/TrackWriterSpec.h" #include "ITStracking/TrackingConfigParam.h" @@ -43,10 +43,10 @@ framework::WorkflowSpec getWorkflow(bool useMC, specs.emplace_back(o2::itsmft::getITSDigitReaderSpec(useMC, false, true, "itsdigits.root")); } if (!upstreamClusters) { - specs.emplace_back(o2::its::getClustererSpec(useMC)); + specs.emplace_back(o2::itsmft::getITSClustererSpec(useMC)); } if (!disableRootOutput) { - specs.emplace_back(o2::its::getClusterWriterSpec(useMC)); + specs.emplace_back(o2::itsmft::getITSClusterWriterSpec(useMC)); } if ((trmode != TrackingMode::Off) && (TrackerParamConfig::Instance().trackingMode != TrackingMode::Off)) { if (useGPUWF) { diff --git a/Detectors/ITSMFT/MFT/workflow/CMakeLists.txt b/Detectors/ITSMFT/MFT/workflow/CMakeLists.txt index acb3d0b3e835f..b83699498a6b8 100644 --- a/Detectors/ITSMFT/MFT/workflow/CMakeLists.txt +++ b/Detectors/ITSMFT/MFT/workflow/CMakeLists.txt @@ -12,8 +12,6 @@ o2_add_library(MFTWorkflow TARGETVARNAME targetName SOURCES src/RecoWorkflow.cxx - src/ClustererSpec.cxx - src/ClusterWriterSpec.cxx src/TrackerSpec.cxx src/TrackReaderSpec.cxx src/TrackWriterSpec.cxx diff --git a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClusterWriterSpec.h b/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClusterWriterSpec.h deleted file mode 100644 index 51dc5a6481eb5..0000000000000 --- a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClusterWriterSpec.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file ClusterWriterSpec.h - -#ifndef O2_MFT_CLUSTERWRITER_H_ -#define O2_MFT_CLUSTERWRITER_H_ - -#include "Framework/DataProcessorSpec.h" - -namespace o2 -{ -namespace mft -{ - -/// create a processor spec -/// write MFT clusters a root file -framework::DataProcessorSpec getClusterWriterSpec(bool useMC); - -} // namespace mft -} // namespace o2 - -#endif /* O2_MFT_CLUSTERWRITER_H */ diff --git a/Detectors/ITSMFT/MFT/workflow/src/ClusterWriterSpec.cxx b/Detectors/ITSMFT/MFT/workflow/src/ClusterWriterSpec.cxx deleted file mode 100644 index c8061310e34f6..0000000000000 --- a/Detectors/ITSMFT/MFT/workflow/src/ClusterWriterSpec.cxx +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file ClusterWriterSpec.cxx - -#include - -#include "MFTWorkflow/ClusterWriterSpec.h" -#include "DPLUtils/MakeRootTreeWriterSpec.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "DataFormatsITSMFT/ROFRecord.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace mft -{ - -template -using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition; -using CompClusType = std::vector; -using PatternsType = std::vector; -using ROFrameRType = std::vector; -using LabelsType = o2::dataformats::MCTruthContainer; -using ROFRecLblT = std::vector; -using namespace o2::header; - -DataProcessorSpec getClusterWriterSpec(bool useMC) -{ - // Spectators for logging - // this is only to restore the original behavior - auto compClustersSize = std::make_shared(0); - auto compClustersSizeGetter = [compClustersSize](CompClusType const& compClusters) { - *compClustersSize = compClusters.size(); - }; - auto logger = [compClustersSize](std::vector const& rofs) { - LOG(info) << "MFTClusterWriter pulled " << *compClustersSize << " clusters, in " << rofs.size() << " RO frames"; - }; - return MakeRootTreeWriterSpec("mft-cluster-writer", - "mftclusters.root", - MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with MFT clusters"}, - BranchDefinition{InputSpec{"compclus", "MFT", "COMPCLUSTERS", 0}, - "MFTClusterComp", - compClustersSizeGetter}, - BranchDefinition{InputSpec{"patterns", "MFT", "PATTERNS", 0}, - "MFTClusterPatt"}, - BranchDefinition{InputSpec{"ROframes", "MFT", "CLUSTERSROF", 0}, - "MFTClustersROF", - logger}, - BranchDefinition{InputSpec{"labels", "MFT", "CLUSTERSMCTR", 0}, - "MFTClusterMCTruth", - (useMC ? 1 : 0), // one branch if mc labels enabled - ""}, - BranchDefinition{InputSpec{"MC2ROframes", "MFT", "CLUSTERSMC2ROF", 0}, - "MFTClustersMC2ROF", - (useMC ? 1 : 0), // one branch if mc labels enabled - ""})(); -} - -} // namespace mft -} // namespace o2 diff --git a/Detectors/ITSMFT/MFT/workflow/src/ClustererSpec.cxx b/Detectors/ITSMFT/MFT/workflow/src/ClustererSpec.cxx deleted file mode 100644 index 766d7c1a0729e..0000000000000 --- a/Detectors/ITSMFT/MFT/workflow/src/ClustererSpec.cxx +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file ClustererSpec.cxx - -#include - -#include "Framework/ControlService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/CCDBParamSpec.h" -#include "MFTWorkflow/ClustererSpec.h" -#include "DataFormatsITSMFT/Digit.h" -#include "ITSMFTReconstruction/ChipMappingMFT.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITSMFT/TopologyDictionary.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/ConstMCTruthContainer.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "DataFormatsParameters/GRPObject.h" -#include "ITSMFTReconstruction/DigitPixelReader.h" -#include "DetectorsBase/GeometryManager.h" -#include "MFTBase/GeometryTGeo.h" -#include "ITSMFTBase/DPLAlpideParam.h" -#include "CommonConstants/LHCConstants.h" -#include "DetectorsCommonDataFormats/DetectorNameConf.h" -#include "ITSMFTReconstruction/ClustererParam.h" - -using namespace o2::framework; -using namespace o2::itsmft; - -namespace o2 -{ -namespace mft -{ - -void ClustererDPL::init(InitContext& ic) -{ - mClusterer = std::make_unique(); - mClusterer->setNChips(o2::itsmft::ChipMappingMFT::getNChips()); - mUseClusterDictionary = !ic.options().get("ignore-cluster-dictionary"); - o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); - mNThreads = std::max(1, ic.options().get("nthreads")); - mState = 1; -} - -void ClustererDPL::run(ProcessingContext& pc) -{ - updateTimeDependentParams(pc); - auto digits = pc.inputs().get>("digits"); - auto rofs = pc.inputs().get>("ROframes"); - - gsl::span mc2rofs; - gsl::span labelbuffer; - if (mUseMC) { - labelbuffer = pc.inputs().get>("labels"); - mc2rofs = pc.inputs().get>("MC2ROframes"); - } - const o2::dataformats::ConstMCTruthContainerView labels(labelbuffer); - - LOG(debug) << "MFTClusterer pulled " << digits.size() << " digits, in " - << rofs.size() << " RO frames"; - - o2::itsmft::DigitPixelReader reader; - reader.setSquashingDepth(mClusterer->getMaxROFDepthToSquash()); - reader.setSquashingDist(mClusterer->getMaxRowColDiffToMask()); // Sharing same parameter/logic with masking - reader.setMaxBCSeparationToSquash(mClusterer->getMaxBCSeparationToSquash()); - reader.setDigits(digits); - reader.setROFRecords(rofs); - if (mUseMC) { - reader.setMC2ROFRecords(mc2rofs); - reader.setDigitsMCTruth(labels.getIndexedSize() > 0 ? &labels : nullptr); - } - reader.init(); - auto orig = o2::header::gDataOriginMFT; - std::vector clusCompVec; - std::vector clusROFVec; - std::vector clusPattVec; - - std::unique_ptr> clusterLabels; - if (mUseMC) { - clusterLabels = std::make_unique>(); - } - mClusterer->process(mNThreads, reader, &clusCompVec, &clusPattVec, &clusROFVec, clusterLabels.get()); - pc.outputs().snapshot(Output{orig, "COMPCLUSTERS", 0}, clusCompVec); - pc.outputs().snapshot(Output{orig, "CLUSTERSROF", 0}, clusROFVec); - pc.outputs().snapshot(Output{orig, "PATTERNS", 0}, clusPattVec); - - if (mUseMC) { - pc.outputs().snapshot(Output{orig, "CLUSTERSMCTR", 0}, *clusterLabels.get()); // at the moment requires snapshot - std::vector clusterMC2ROframes(mc2rofs.size()); - for (int i = mc2rofs.size(); i--;) { - clusterMC2ROframes[i] = mc2rofs[i]; // Simply, replicate it from digits ? - } - pc.outputs().snapshot(Output{orig, "CLUSTERSMC2ROF", 0}, clusterMC2ROframes); - } - - // TODO: in principle, after masking "overflow" pixels the MC2ROFRecord maxROF supposed to change, nominally to minROF - // -> consider recalculationg maxROF - LOG(debug) << "MFTClusterer pushed " << clusCompVec.size() << " compressed clusters, in " << clusROFVec.size() << " RO frames"; -} - -///_______________________________________ -void ClustererDPL::updateTimeDependentParams(ProcessingContext& pc) -{ - o2::base::GRPGeomHelper::instance().checkUpdates(pc); - static bool initOnceDone = false; - if (!initOnceDone) { // this params need to be queried only once - initOnceDone = true; - pc.inputs().get("cldict"); // just to trigger the finaliseCCDB - pc.inputs().get*>("alppar"); - pc.inputs().get*>("cluspar"); - mClusterer->setContinuousReadOut(o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::MFT)); - // settings for the fired pixel overflow masking - const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); - const auto& clParams = o2::itsmft::ClustererParam::Instance(); - if (clParams.maxBCDiffToMaskBias > 0 && clParams.maxBCDiffToSquashBias > 0) { - LOGP(fatal, "maxBCDiffToMaskBias = {} and maxBCDiffToSquashBias = {} cannot be set at the same time. Either set masking or squashing with a BCDiff > 0", clParams.maxBCDiffToMaskBias, clParams.maxBCDiffToSquashBias); - } - mClusterer->setDropHugeClusters(clParams.dropHugeClusters); - auto nbc = clParams.maxBCDiffToMaskBias; - nbc += mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); - mClusterer->setMaxBCSeparationToMask(nbc); - mClusterer->setMaxRowColDiffToMask(clParams.maxRowColDiffToMask); - // Squasher - int rofBC = mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); // ROF length in BC - mClusterer->setMaxBCSeparationToSquash(rofBC + clParams.maxBCDiffToSquashBias); - int nROFsToSquash = 0; // squashing disabled if no reset due to maxSOTMUS>0. - if (clParams.maxSOTMUS > 0 && rofBC > 0) { - nROFsToSquash = 2 + int(clParams.maxSOTMUS / (rofBC * o2::constants::lhc::LHCBunchSpacingMUS)); // use squashing - } - mClusterer->setMaxROFDepthToSquash(nROFsToSquash); - mClusterer->print(); - } - // we may have other params which need to be queried regularly -} - -///_______________________________________ -void ClustererDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) -{ - if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { - return; - } - if (matcher == ConcreteDataMatcher("MFT", "CLUSDICT", 0)) { - LOG(info) << "cluster dictionary updated" << (!mUseClusterDictionary ? " but its using is disabled" : ""); - if (mUseClusterDictionary) { - mClusterer->setDictionary((const TopologyDictionary*)obj); - } - return; - } - // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level - if (matcher == ConcreteDataMatcher("MFT", "ALPIDEPARAM", 0)) { - LOG(info) << "Alpide param updated"; - const auto& par = o2::itsmft::DPLAlpideParam::Instance(); - par.printKeyValues(); - return; - } - if (matcher == ConcreteDataMatcher("MFT", "CLUSPARAM", 0)) { - LOG(info) << "Cluster param updated"; - const auto& par = o2::itsmft::ClustererParam::Instance(); - par.printKeyValues(); - return; - } -} - -DataProcessorSpec getClustererSpec(bool useMC) -{ - std::vector inputs; - inputs.emplace_back("digits", "MFT", "DIGITS", 0, Lifetime::Timeframe); - inputs.emplace_back("ROframes", "MFT", "DIGITSROF", 0, Lifetime::Timeframe); - inputs.emplace_back("cldict", "MFT", "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec("MFT/Calib/ClusterDictionary")); - inputs.emplace_back("cluspar", "MFT", "CLUSPARAM", 0, Lifetime::Condition, ccdbParamSpec("MFT/Config/ClustererParam")); - inputs.emplace_back("alppar", "MFT", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("MFT/Config/AlpideParam")); - auto ggRequest = std::make_shared(false, // orbitResetTime - true, // GRPECS=true - false, // GRPLHCIF - false, // GRPMagField - false, // askMatLUT - o2::base::GRPGeomRequest::None, // geometry - inputs, - true); - std::vector outputs; - outputs.emplace_back("MFT", "COMPCLUSTERS", 0, Lifetime::Timeframe); - outputs.emplace_back("MFT", "PATTERNS", 0, Lifetime::Timeframe); - outputs.emplace_back("MFT", "CLUSTERSROF", 0, Lifetime::Timeframe); - - if (useMC) { - inputs.emplace_back("labels", "MFT", "DIGITSMCTR", 0, Lifetime::Timeframe); - inputs.emplace_back("MC2ROframes", "MFT", "DIGITSMC2ROF", 0, Lifetime::Timeframe); - outputs.emplace_back("MFT", "CLUSTERSMCTR", 0, Lifetime::Timeframe); - outputs.emplace_back("MFT", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe); - } - - return DataProcessorSpec{ - "mft-clusterer", - inputs, - outputs, - AlgorithmSpec{adaptFromTask(ggRequest, useMC)}, - Options{ - {"ignore-cluster-dictionary", VariantType::Bool, false, {"do not use cluster dictionary, always store explicit patterns"}}, - {"nthreads", VariantType::Int, 1, {"Number of clustering threads"}}}}; -} - -} // namespace mft -} // namespace o2 diff --git a/Detectors/ITSMFT/MFT/workflow/src/RecoWorkflow.cxx b/Detectors/ITSMFT/MFT/workflow/src/RecoWorkflow.cxx index 615c9c1b275d4..5d85c0ef81670 100644 --- a/Detectors/ITSMFT/MFT/workflow/src/RecoWorkflow.cxx +++ b/Detectors/ITSMFT/MFT/workflow/src/RecoWorkflow.cxx @@ -12,9 +12,9 @@ /// @file RecoWorkflow.cxx #include +#include "ITSMFTWorkflow/ClustererSpec.h" +#include "ITSMFTWorkflow/ClusterWriterSpec.h" #include "MFTWorkflow/RecoWorkflow.h" -#include "MFTWorkflow/ClustererSpec.h" -#include "MFTWorkflow/ClusterWriterSpec.h" #include "MFTWorkflow/TrackerSpec.h" #include "MFTWorkflow/TrackWriterSpec.h" #include "ITSMFTWorkflow/DigitReaderSpec.h" @@ -52,10 +52,10 @@ framework::WorkflowSpec getWorkflow( } } if (!upstreamClusters) { - specs.emplace_back(o2::mft::getClustererSpec(useMC)); + specs.emplace_back(o2::itsmft::getMFTClustererSpec(useMC)); } if (!disableRootOutput) { - specs.emplace_back(o2::mft::getClusterWriterSpec(useMC)); + specs.emplace_back(o2::itsmft::getMFTClusterWriterSpec(useMC)); } if (runTracking) { diff --git a/Detectors/ITSMFT/MFT/workflow/src/mft-cluster-writer-workflow.cxx b/Detectors/ITSMFT/MFT/workflow/src/mft-cluster-writer-workflow.cxx index f42b2e0c92a4a..b656970693808 100644 --- a/Detectors/ITSMFT/MFT/workflow/src/mft-cluster-writer-workflow.cxx +++ b/Detectors/ITSMFT/MFT/workflow/src/mft-cluster-writer-workflow.cxx @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "MFTWorkflow/ClusterWriterSpec.h" +#include "ITSMFTWorkflow/ClusterWriterSpec.h" #include "Framework/ConfigParamSpec.h" #include "Framework/CompletionPolicyHelpers.h" @@ -34,6 +34,6 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { auto useMC = !configcontext.options().get("disable-mc"); WorkflowSpec specs; - specs.emplace_back(o2::mft::getClusterWriterSpec(useMC)); + specs.emplace_back(o2::itsmft::getMFTClusterWriterSpec(useMC)); return specs; } diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h index c66468905d0aa..0bdbb701a9356 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h @@ -215,13 +215,15 @@ class Clusterer int getMaxRowColDiffToMask() const { return mMaxRowColDiffToMask; } void setMaxRowColDiffToMask(int v) { mMaxRowColDiffToMask = v; } - int getMaxROFDepthToSquash() const { return mSquashingDepth; } + int getMaxROFDepthToSquash(int layer = -1) const { return (layer < 0) ? mSquashingDepth : mSquashingLayerDepth[layer]; } void setMaxROFDepthToSquash(int v) { mSquashingDepth = v; } + void addMaxROFDepthToSquash(int v) { mSquashingLayerDepth.push_back(v); } - int getMaxBCSeparationToSquash() const { return mMaxBCSeparationToSquash; } + int getMaxBCSeparationToSquash(int layer = -1) const { return (layer < 0) ? mMaxBCSeparationToSquash : mMaxBCSeparationToSquashLayer[layer]; } void setMaxBCSeparationToSquash(int n) { mMaxBCSeparationToSquash = n; } + void addMaxBCSeparationToSquash(int n) { mMaxBCSeparationToSquashLayer.push_back(n); } - void print() const; + void print(bool showTiming = true) const; void clear(); void reset(); @@ -245,7 +247,7 @@ class Clusterer bool mContinuousReadout = true; ///< flag continuous readout bool mDropHugeClusters = false; ///< don't include clusters that would be split in more than one - ///< mask continuosly fired pixels in frames separated by less than this amount of BCs (fired from hit in prev. ROF) + ///< mask continuously fired pixels in frames separated by less than this amount of BCs (fired from hit in prev. ROF) int mMaxBCSeparationToMask = 6000. / o2::constants::lhc::LHCBunchSpacingNS + 10; int mMaxRowColDiffToMask = 0; ///< provide their difference in col/row is <= than this int mNHugeClus = 0; ///< number of encountered huge clusters @@ -253,6 +255,8 @@ class Clusterer ///< Squashing options int mSquashingDepth = 0; ///< squashing is applied to next N rofs int mMaxBCSeparationToSquash = 6000. / o2::constants::lhc::LHCBunchSpacingNS + 10; + std::vector mSquashingLayerDepth; + std::vector mMaxBCSeparationToSquashLayer; std::vector> mThreads; // buffers for threads std::vector mChips; // currently processed ROF's chips data @@ -288,7 +292,7 @@ void Clusterer::streamCluster(const std::vector& pixbuf, const std::a uint16_t row = bbox.rowMin, col = bbox.colMin; if (pattID == CompCluster::InvalidPatternID || pattIdConverter.isGroup(pattID)) { if (pattID != CompCluster::InvalidPatternID) { - // For groupped topologies, the reference pixel is the COG pixel + // For grouped topologies, the reference pixel is the COG pixel float xCOG = 0., zCOG = 0.; ClusterPattern::getCOG(rowSpanW, colSpanW, patt.data(), xCOG, zCOG); row += round(xCOG); diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ClustererParam.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ClustererParam.h index a71e5f3095b06..3188a4f3b0010 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ClustererParam.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ClustererParam.h @@ -29,16 +29,26 @@ template struct ClustererParam : public o2::conf::ConfigurableParamHelper> { static_assert(N == o2::detectors::DetID::ITS || N == o2::detectors::DetID::MFT, "only DetID::ITS or DetID:: MFT are allowed"); + static constexpr int getNLayers() + { + return N == o2::detectors::DetID::ITS ? 7 : 10; + } + static constexpr std::string_view getParamName() { return N == o2::detectors::DetID::ITS ? ParamName[0] : ParamName[1]; } - int maxRowColDiffToMask = DEFRowColDiffToMask(); ///< pixel may be masked as overflow if such a neighbour in prev frame was fired - int maxBCDiffToMaskBias = 10; ///< mask if 2 ROFs differ by <= StrobeLength + Bias BCs, use value <0 to disable masking - int maxBCDiffToSquashBias = -10; ///< squash if 2 ROFs differ by <= StrobeLength + Bias BCs, use value <0 to disable squashing - float maxSOTMUS = 8.; ///< max expected signal over threshold in \mus - bool dropHugeClusters = false; ///< option to drop huge clusters (mitigate beam background) + int maxRowColDiffToMask = DEFRowColDiffToMask(); ///< pixel may be masked as overflow if such a neighbour in prev frame was fired + int maxBCDiffToMaskBias = 10; ///< mask if 2 ROFs differ by <= StrobeLength + Bias BCs, use value <0 to disable masking + int maxBCDiffToSquashBias = -10; ///< squash if 2 ROFs differ by <= StrobeLength + Bias BCs, use value <0 to disable squashing + float maxSOTMUS = 8.; ///< max expected signal over threshold in \mus + bool dropHugeClusters = false; ///< option to drop huge clusters (mitigate beam background) + int maxBCDiffToSquashBiasLayer[getNLayers()] = {}; ///< squash mask per layer + int getMaxBCDiffToSquashBias(int layer) const noexcept + { + return maxBCDiffToSquashBiasLayer[layer] ? maxBCDiffToSquashBiasLayer[layer] : maxBCDiffToSquashBias; + } O2ParamDef(ClustererParam, getParamName().data()); @@ -46,7 +56,7 @@ struct ClustererParam : public o2::conf::ConfigurableParamHelper(nFired, nThreads); #ifndef WITH_OPENMP nThreads = 1; #endif @@ -173,7 +168,7 @@ void Clusterer::ClustererThread::process(uint16_t chip, uint16_t nChips, CompClu const ConstMCTruth* labelsDigPtr, MCTruth* labelsClPtr, const ROFRecord& rofPtr) { if (stats.empty() || stats.back().firstChip + stats.back().nChips != chip) { // there is a jump, register new block - stats.emplace_back(ThreadStat{chip, 0, uint32_t(compClusPtr->size()), patternsPtr ? uint32_t(patternsPtr->size()) : 0, 0, 0}); + stats.emplace_back(ThreadStat{.firstChip = chip, .nChips = 0, .firstClus = uint32_t(compClusPtr->size()), .firstPatt = patternsPtr ? uint32_t(patternsPtr->size()) : 0, .nClus = 0, .nPatt = 0}); } for (int ic = 0; ic < nChips; ic++) { auto* curChipData = parent->mFiredChipsPtr[chip + ic]; @@ -476,22 +471,31 @@ void Clusterer::clear() } //__________________________________________________ -void Clusterer::print() const +void Clusterer::print(bool showsTiming) const { // print settings - LOGP(info, "Clusterizer squashes overflow pixels separated by {} BC and <= {} in row/col seeking down to {} neighbour ROFs", mMaxBCSeparationToSquash, mMaxRowColDiffToMask, mSquashingDepth); + if (mSquashingLayerDepth.empty()) { + LOGP(info, "Clusterizer squashes overflow pixels separated by {} BC and <= {} in row/col seeking down to {} neighbour ROFs", mMaxBCSeparationToSquash, mMaxRowColDiffToMask, mSquashingDepth); + } else { + LOGP(info, "Clusterizer squashes overflow pixels <= {} in row/col", mMaxRowColDiffToMask); + for (size_t i{0}; i < mSquashingLayerDepth.size(); ++i) { + LOGP(info, "\tlay:{} separated by {} BC seeking down to {} neighbour ROFs", i, mMaxBCSeparationToSquashLayer[i], mSquashingLayerDepth[i]); + } + } LOGP(info, "Clusterizer masks overflow pixels separated by < {} BC and <= {} in row/col", mMaxBCSeparationToMask, mMaxRowColDiffToMask); LOGP(info, "Clusterizer does {} drop huge clusters", mDropHugeClusters ? "" : "not"); + if (showsTiming) { #ifdef _PERFORM_TIMING_ - auto& tmr = const_cast(mTimer); // ugly but this is what root does internally - auto& tmrm = const_cast(mTimerMerge); - LOG(info) << "Inclusive clusterization timing (w/o disk IO): Cpu: " << tmr.CpuTime() - << " Real: " << tmr.RealTime() << " s in " << tmr.Counter() << " slots"; - LOG(info) << "Threads output merging timing : Cpu: " << tmrm.CpuTime() - << " Real: " << tmrm.RealTime() << " s in " << tmrm.Counter() << " slots"; + auto& tmr = const_cast(mTimer); // ugly but this is what root does internally + auto& tmrm = const_cast(mTimerMerge); + LOG(info) << "Inclusive clusterization timing (w/o disk IO): Cpu: " << tmr.CpuTime() + << " Real: " << tmr.RealTime() << " s in " << tmr.Counter() << " slots"; + LOG(info) << "Threads output merging timing : Cpu: " << tmrm.CpuTime() + << " Real: " << tmrm.RealTime() << " s in " << tmrm.Counter() << " slots"; #endif + } } //__________________________________________________ diff --git a/Detectors/ITSMFT/common/reconstruction/src/DigitPixelReader.cxx b/Detectors/ITSMFT/common/reconstruction/src/DigitPixelReader.cxx index b8d88a6fc4223..5c1dbde074649 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/DigitPixelReader.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/DigitPixelReader.cxx @@ -330,3 +330,14 @@ void DigitPixelReader::clear() mROFRecVec = gsl::span(); mMC2ROFRecVec = gsl::span(); } + +//______________________________________________________________________________ +void DigitPixelReader::reset() +{ + clear(); + mSquashedDigitsMask.clear(); + mBookmarkNextROFs.clear(); + mIdDig = 0; + mIdROF = 0; + mIdROFLast = 0; +} diff --git a/Detectors/ITSMFT/common/workflow/CMakeLists.txt b/Detectors/ITSMFT/common/workflow/CMakeLists.txt index 63cd8d6c0bcee..ead08c4422260 100644 --- a/Detectors/ITSMFT/common/workflow/CMakeLists.txt +++ b/Detectors/ITSMFT/common/workflow/CMakeLists.txt @@ -11,6 +11,8 @@ o2_add_library(ITSMFTWorkflow SOURCES src/ClusterReaderSpec.cxx + src/ClusterWriterSpec.cxx + src/ClustererSpec.cxx src/DigitWriterSpec.cxx src/DigitReaderSpec.cxx src/STFDecoderSpec.cxx diff --git a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterReaderSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterReaderSpec.h index 99318df1cd9d9..82e3890de7475 100644 --- a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterReaderSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterReaderSpec.h @@ -23,46 +23,51 @@ #include "DataFormatsITSMFT/CompCluster.h" #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" +#include "ITSMFTBase/DPLAlpideParam.h" #include "DataFormatsITSMFT/ROFRecord.h" #include "DetectorsCommonDataFormats/DetID.h" using namespace o2::framework; -namespace o2 -{ -namespace itsmft +namespace o2::itsmft { +template class ClusterReader : public Task { public: + static constexpr o2::detectors::DetID ID{N == o2::detectors::DetID::ITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT}; + static constexpr o2::header::DataOrigin Origin{(N == o2::detectors::DetID::ITS) ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; + static constexpr int NLayers{o2::itsmft::DPLAlpideParam::supportsStaggering() ? o2::itsmft::DPLAlpideParam::getNLayers() : 1}; + ClusterReader() = delete; - ClusterReader(o2::detectors::DetID id, bool useMC, bool usePatterns = true, bool triggers = true); + ClusterReader(bool useMC, bool usePatterns = true, bool triggers = true); ~ClusterReader() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; protected: void connectTree(const std::string& filename); + template + void setBranchAddress(const std::string& base, Ptr& addr, int layer); + std::string getBranchName(const std::string& base, int index) const; - std::vector mClusROFRec, *mClusROFRecPtr = &mClusROFRec; - std::vector mClusterCompArray, *mClusterCompArrayPtr = &mClusterCompArray; - std::vector mPatternsArray, *mPatternsArrayPtr = &mPatternsArray; - o2::dataformats::MCTruthContainer mClusterMCTruth, *mClusterMCTruthPtr = &mClusterMCTruth; - std::vector mClusMC2ROFs, *mClusMC2ROFsPtr = &mClusMC2ROFs; - - o2::header::DataOrigin mOrigin = o2::header::gDataOriginInvalid; + std::array*, NLayers> mClusROFRec; + std::array*, NLayers> mClusterCompArray; + std::array*, NLayers> mPatternsArray; + std::array*, NLayers> mClusterMCTruth; + std::array*, NLayers> mClusMC2ROFs; std::unique_ptr mFile; std::unique_ptr mTree; - bool mUseMC = true; // use MC truth + bool mUseMC = true; // use MC truth bool mUsePatterns = true; // send patterns bool mTriggerOut = true; // send dummy triggers vector - std::string mDetName = ""; - std::string mDetNameLC = ""; - std::string mFileName = ""; + std::string mDetName; + std::string mDetNameLC; + std::string mFileName; std::string mClusTreeName = "o2sim"; std::string mClusROFBranchName = "ClustersROF"; std::string mClusterPattBranchName = "ClusterPatt"; @@ -71,24 +76,18 @@ class ClusterReader : public Task std::string mClustMC2ROFBranchName = "ClustersMC2ROF"; }; -class ITSClusterReader : public ClusterReader +class ITSClusterReader : public ClusterReader { public: ITSClusterReader(bool useMC = true, bool usePatterns = true, bool triggerOut = true) - : ClusterReader(o2::detectors::DetID::ITS, useMC, usePatterns, triggerOut) - { - mOrigin = o2::header::gDataOriginITS; - } + : ClusterReader(useMC, usePatterns, triggerOut) {} }; -class MFTClusterReader : public ClusterReader +class MFTClusterReader : public ClusterReader { public: MFTClusterReader(bool useMC = true, bool usePatterns = true, bool triggerOut = true) - : ClusterReader(o2::detectors::DetID::MFT, useMC, usePatterns, triggerOut) - { - mOrigin = o2::header::gDataOriginMFT; - } + : ClusterReader(useMC, usePatterns, triggerOut) {} }; /// create a processor spec @@ -96,7 +95,6 @@ class MFTClusterReader : public ClusterReader framework::DataProcessorSpec getITSClusterReaderSpec(bool useMC = true, bool usePatterns = true, bool useTriggers = true); framework::DataProcessorSpec getMFTClusterReaderSpec(bool useMC = true, bool usePatterns = true, bool useTriggers = true); -} // namespace itsmft -} // namespace o2 +} // namespace o2::itsmft #endif /* O2_ITSMFT_CLUSTERREADER */ diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClusterWriterSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterWriterSpec.h similarity index 73% rename from Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClusterWriterSpec.h rename to Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterWriterSpec.h index 42b96786af27a..5ae371e7e09c4 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClusterWriterSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterWriterSpec.h @@ -11,21 +11,19 @@ /// @file ClusterWriterSpec.h -#ifndef O2_ITS_CLUSTERWRITER -#define O2_ITS_CLUSTERWRITER +#ifndef O2_ITSMFT_CLUSTERWRITER +#define O2_ITSMFT_CLUSTERWRITER #include "Framework/DataProcessorSpec.h" -namespace o2 -{ -namespace its +namespace o2::itsmft { -/// create a processor spec -/// write ITS clusters to ROOT file +template framework::DataProcessorSpec getClusterWriterSpec(bool useMC); +framework::DataProcessorSpec getITSClusterWriterSpec(bool useMC); +framework::DataProcessorSpec getMFTClusterWriterSpec(bool useMC); -} // namespace its -} // namespace o2 +} // namespace o2::itsmft #endif /* O2_ITS_CLUSTERWRITER */ diff --git a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClustererSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClustererSpec.h similarity index 64% rename from Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClustererSpec.h rename to Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClustererSpec.h index f0a763597ff74..b6ebc282c2a27 100644 --- a/Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClustererSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClustererSpec.h @@ -11,24 +11,27 @@ /// @file ClustererSpec.h -#ifndef O2_MFT_CLUSTERERDPL_H_ -#define O2_MFT_CLUSTERERDPL_H_ +#ifndef O2_ITSMFT_CLUSTERERDPL_H_ +#define O2_ITSMFT_CLUSTERERDPL_H_ -#include #include "DetectorsBase/GRPGeomHelper.h" #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" #include "ITSMFTReconstruction/Clusterer.h" +#include "ITSMFTBase/DPLAlpideParam.h" using namespace o2::framework; -namespace o2 -{ -namespace mft +namespace o2::itsmft { +template class ClustererDPL : public Task { + static constexpr o2::detectors::DetID ID{N == o2::detectors::DetID::ITS ? o2::detectors::DetID::ITS : o2::detectors::DetID::MFT}; + static constexpr o2::header::DataOrigin Origin{N == o2::detectors::DetID::ITS ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; + static constexpr int NLayers{o2::itsmft::DPLAlpideParam::supportsStaggering() ? o2::itsmft::DPLAlpideParam::getNLayers() : 1}; + public: ClustererDPL(std::shared_ptr gr, bool useMC) : mGGCCDBRequest(gr), mUseMC(useMC) {} ~ClustererDPL() override = default; @@ -39,20 +42,19 @@ class ClustererDPL : public Task private: void updateTimeDependentParams(ProcessingContext& pc); - int mState = 0; + std::string mDetName; bool mUseMC = true; bool mUseClusterDictionary = true; int mNThreads = 1; - std::unique_ptr mFile = nullptr; std::unique_ptr mClusterer = nullptr; std::shared_ptr mGGCCDBRequest; + int mLayers{NLayers}; + std::vector mFilter; }; -/// create a processor spec -/// run MFT cluster finder -framework::DataProcessorSpec getClustererSpec(bool useMC); +framework::DataProcessorSpec getITSClustererSpec(bool useMC); +framework::DataProcessorSpec getMFTClustererSpec(bool useMC); -} // namespace mft -} // namespace o2 +} // namespace o2::itsmft #endif /* O2_MFT_CLUSTERERDPL */ diff --git a/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx index ea906056c7898..bc6418a077810 100644 --- a/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx @@ -12,15 +12,16 @@ /// @file ClusterReaderSpec.cxx #include +#include -#include "TTree.h" +#include #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/Logger.h" #include "ITSMFTWorkflow/ClusterReaderSpec.h" +#include "ITSMFTBase/DPLAlpideParam.h" #include "DataFormatsITSMFT/PhysTrigger.h" -#include #include "CommonUtils/NameConf.h" using namespace o2::framework; @@ -31,45 +32,48 @@ namespace o2 namespace itsmft { -ClusterReader::ClusterReader(o2::detectors::DetID id, bool useMC, bool usePatterns, bool triggerOut) +template +ClusterReader::ClusterReader(bool useMC, bool usePatterns, bool triggerOut) : mUseMC(useMC), mUsePatterns(usePatterns), mTriggerOut(triggerOut), mDetName(Origin.as()), mDetNameLC(mDetName) { - assert(id == o2::detectors::DetID::ITS || id == o2::detectors::DetID::MFT); - mDetNameLC = mDetName = id.getName(); - mUseMC = useMC; - mUsePatterns = usePatterns; - mTriggerOut = triggerOut; std::transform(mDetNameLC.begin(), mDetNameLC.end(), mDetNameLC.begin(), ::tolower); + + mClusROFRec.fill(nullptr); + mClusterCompArray.fill(nullptr); + mPatternsArray.fill(nullptr); + mClusterMCTruth.fill(nullptr); + mClusMC2ROFs.fill(nullptr); } -void ClusterReader::init(InitContext& ic) +template +void ClusterReader::init(InitContext& ic) { mFileName = o2::utils::Str::concat_string(o2::utils::Str::rectifyDirectory(ic.options().get("input-dir")), ic.options().get((mDetNameLC + "-cluster-infile").c_str())); connectTree(mFileName); } -void ClusterReader::run(ProcessingContext& pc) +template +void ClusterReader::run(ProcessingContext& pc) { auto ent = mTree->GetReadEntry() + 1; assert(ent < mTree->GetEntries()); // this should not happen mTree->GetEntry(ent); - LOG(info) << mDetName << "ClusterReader pushes " << mClusROFRec.size() << " ROFRecords," - << mClusterCompArray.size() << " compact clusters at entry " << ent; - - // This is a very ugly way of providing DataDescription, which anyway does not need to contain detector name. - // To be fixed once the names-definition class is ready - pc.outputs().snapshot(Output{mOrigin, "CLUSTERSROF", 0}, mClusROFRec); - pc.outputs().snapshot(Output{mOrigin, "COMPCLUSTERS", 0}, mClusterCompArray); - if (mUsePatterns) { - pc.outputs().snapshot(Output{mOrigin, "PATTERNS", 0}, mPatternsArray); - } - if (mUseMC) { - pc.outputs().snapshot(Output{mOrigin, "CLUSTERSMCTR", 0}, mClusterMCTruth); - pc.outputs().snapshot(Output{mOrigin, "CLUSTERSMC2ROF", 0}, mClusMC2ROFs); + + for (uint32_t iLayer = 0; iLayer < NLayers; ++iLayer) { + LOG(info) << mDetName << "ClusterReader:" << iLayer << " pushes " << mClusROFRec[iLayer]->size() << " ROFRecords, " << mClusterCompArray[iLayer]->size() << " compact clusters at entry " << ent; + pc.outputs().snapshot(Output{Origin, "CLUSTERSROF", iLayer}, *mClusROFRec[iLayer]); + pc.outputs().snapshot(Output{Origin, "COMPCLUSTERS", iLayer}, *mClusterCompArray[iLayer]); + if (mUsePatterns) { + pc.outputs().snapshot(Output{Origin, "PATTERNS", iLayer}, *mPatternsArray[iLayer]); + } + if (mUseMC) { + pc.outputs().snapshot(Output{Origin, "CLUSTERSMCTR", iLayer}, *mClusterMCTruth[iLayer]); + pc.outputs().snapshot(Output{Origin, "CLUSTERSMC2ROF", iLayer}, *mClusMC2ROFs[iLayer]); + } } if (mTriggerOut) { std::vector dummyTrig; - pc.outputs().snapshot(Output{mOrigin, "PHYSTRIG", 0}, dummyTrig); + pc.outputs().snapshot(Output{Origin, "PHYSTRIG", 0}, dummyTrig); } if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { pc.services().get().endOfStream(); @@ -77,7 +81,8 @@ void ClusterReader::run(ProcessingContext& pc) } } -void ClusterReader::connectTree(const std::string& filename) +template +void ClusterReader::connectTree(const std::string& filename) { mTree.reset(nullptr); // in case it was already loaded mFile.reset(TFile::Open(filename.c_str())); @@ -85,70 +90,89 @@ void ClusterReader::connectTree(const std::string& filename) mTree.reset((TTree*)mFile->Get(mClusTreeName.c_str())); assert(mTree); - mTree->SetBranchAddress((mDetName + mClusROFBranchName).c_str(), &mClusROFRecPtr); - mTree->SetBranchAddress((mDetName + mClusterCompBranchName).c_str(), &mClusterCompArrayPtr); - if (mUsePatterns) { - mTree->SetBranchAddress((mDetName + mClusterPattBranchName).c_str(), &mPatternsArrayPtr); - } - if (mUseMC) { - if (mTree->GetBranch((mDetName + mClustMCTruthBranchName).c_str()) && - mTree->GetBranch((mDetName + mClustMC2ROFBranchName).c_str())) { - mTree->SetBranchAddress((mDetName + mClustMCTruthBranchName).c_str(), &mClusterMCTruthPtr); - mTree->SetBranchAddress((mDetName + mClustMC2ROFBranchName).c_str(), &mClusMC2ROFsPtr); - } else { - LOG(info) << "MC-truth is missing"; - mUseMC = false; + for (uint32_t iLayer = 0; iLayer < NLayers; ++iLayer) { + setBranchAddress(mClusROFBranchName, mClusROFRec[iLayer], iLayer); + setBranchAddress(mClusterCompBranchName, mClusterCompArray[iLayer], iLayer); + if (mUsePatterns) { + setBranchAddress(mClusterPattBranchName, mPatternsArray[iLayer], iLayer); + } + if (mUseMC) { + if (mTree->GetBranch(getBranchName(mClustMCTruthBranchName, iLayer).c_str()) && + mTree->GetBranch(getBranchName(mClustMC2ROFBranchName, iLayer).c_str())) { + setBranchAddress(mClustMCTruthBranchName, mClusterMCTruth[iLayer], iLayer); + setBranchAddress(mClustMC2ROFBranchName, mClusMC2ROFs[iLayer], iLayer); + } else { + LOG(info) << "MC-truth is missing"; + mUseMC = false; + } } } LOG(info) << "Loaded tree from " << filename << " with " << mTree->GetEntries() << " entries"; } -DataProcessorSpec getITSClusterReaderSpec(bool useMC, bool usePatterns, bool triggerOut) +template +std::string ClusterReader::getBranchName(const std::string& base, int index) const +{ + if constexpr (o2::itsmft::DPLAlpideParam::supportsStaggering()) { + return mDetName + base + "_" + std::to_string(index); + } + return mDetName + base; +} + +template +template +void ClusterReader::setBranchAddress(const std::string& base, Ptr& addr, int layer) { - std::vector outputSpec; - outputSpec.emplace_back("ITS", "CLUSTERSROF", 0, Lifetime::Timeframe); - outputSpec.emplace_back("ITS", "COMPCLUSTERS", 0, Lifetime::Timeframe); - if (usePatterns) { - outputSpec.emplace_back("ITS", "PATTERNS", 0, Lifetime::Timeframe); + const auto name = getBranchName(base, layer); + if (Int_t ret = mTree->SetBranchAddress(name.c_str(), &addr); ret != 0) { + LOGP(fatal, "failed to set branch address for {} ret={}", name, ret); } - if (useMC) { - outputSpec.emplace_back("ITS", "CLUSTERSMCTR", 0, Lifetime::Timeframe); - outputSpec.emplace_back("ITS", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe); +} + +namespace +{ +template +std::vector makeOutChannels(o2::header::DataOrigin detOrig, bool mctruth, bool usePatterns, bool triggerOut) +{ + std::vector outputs; + for (uint32_t iLayer = 0; iLayer < ((o2::itsmft::DPLAlpideParam::supportsStaggering()) ? o2::itsmft::DPLAlpideParam::getNLayers() : 1); ++iLayer) { + outputs.emplace_back(detOrig, "CLUSTERSROF", iLayer, Lifetime::Timeframe); + outputs.emplace_back(detOrig, "COMPCLUSTERS", iLayer, Lifetime::Timeframe); + if (usePatterns) { + outputs.emplace_back(detOrig, "PATTERNS", iLayer, Lifetime::Timeframe); + } + if (mctruth) { + outputs.emplace_back(detOrig, "CLUSTERSMCTR", iLayer, Lifetime::Timeframe); + outputs.emplace_back(detOrig, "CLUSTERSMC2ROF", iLayer, Lifetime::Timeframe); + } } if (triggerOut) { - outputSpec.emplace_back("ITS", "PHYSTRIG", 0, Lifetime::Timeframe); + outputs.emplace_back(detOrig, "PHYSTRIG", 0, Lifetime::Timeframe); } + return outputs; +} +} // namespace + +DataProcessorSpec getITSClusterReaderSpec(bool useMC, bool usePatterns, bool triggerOut) +{ return DataProcessorSpec{ - "its-cluster-reader", - Inputs{}, - outputSpec, - AlgorithmSpec{adaptFromTask(useMC, usePatterns, triggerOut)}, - Options{ + .name = "its-cluster-reader", + .inputs = Inputs{}, + .outputs = makeOutChannels("ITS", useMC, usePatterns, triggerOut), + .algorithm = AlgorithmSpec{adaptFromTask(useMC, usePatterns, triggerOut)}, + .options = Options{ {"its-cluster-infile", VariantType::String, "o2clus_its.root", {"Name of the input cluster file"}}, {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } DataProcessorSpec getMFTClusterReaderSpec(bool useMC, bool usePatterns, bool triggerOut) { - std::vector outputSpec; - outputSpec.emplace_back("MFT", "CLUSTERSROF", 0, Lifetime::Timeframe); - outputSpec.emplace_back("MFT", "COMPCLUSTERS", 0, Lifetime::Timeframe); - if (usePatterns) { - outputSpec.emplace_back("MFT", "PATTERNS", 0, Lifetime::Timeframe); - } - if (useMC) { - outputSpec.emplace_back("MFT", "CLUSTERSMCTR", 0, Lifetime::Timeframe); - outputSpec.emplace_back("MFT", "CLUSTERSMC2ROF", 0, Lifetime::Timeframe); - } - if (triggerOut) { - outputSpec.emplace_back("MFT", "PHYSTRIG", 0, Lifetime::Timeframe); - } return DataProcessorSpec{ - "mft-cluster-reader", - Inputs{}, - outputSpec, - AlgorithmSpec{adaptFromTask(useMC, usePatterns, triggerOut)}, - Options{ + .name = "mft-cluster-reader", + .inputs = Inputs{}, + .outputs = makeOutChannels("MFT", useMC, usePatterns, triggerOut), + .algorithm = AlgorithmSpec{adaptFromTask(useMC, usePatterns, triggerOut)}, + .options = Options{ {"mft-cluster-infile", VariantType::String, "mftclusters.root", {"Name of the input cluster file"}}, {"input-dir", VariantType::String, "none", {"Input directory"}}}}; } diff --git a/Detectors/ITSMFT/common/workflow/src/ClusterWriterSpec.cxx b/Detectors/ITSMFT/common/workflow/src/ClusterWriterSpec.cxx new file mode 100644 index 0000000000000..c1900c346133b --- /dev/null +++ b/Detectors/ITSMFT/common/workflow/src/ClusterWriterSpec.cxx @@ -0,0 +1,107 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClusterWriterSpec.cxx + +#include +#include +#include +#include +#include + +#include "Framework/ConcreteDataMatcher.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "ITSMFTWorkflow/ClusterWriterSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTruthContainer.h" + +using namespace o2::framework; + +namespace o2::itsmft +{ + +template +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition; +using CompClusType = std::vector; +using PatternsType = std::vector; +using ROFrameRType = std::vector; +using LabelsType = o2::dataformats::MCTruthContainer; +using ROFRecLblT = std::vector; +using namespace o2::header; + +template +DataProcessorSpec getClusterWriterSpec(bool useMC) +{ + static constexpr o2::header::DataOrigin Origin{N == o2::detectors::DetID::ITS ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; + constexpr int NLayers = (DPLAlpideParam::supportsStaggering()) ? DPLAlpideParam::getNLayers() : 1; + const auto detName = Origin.as(); + // Spectators for logging + auto compClusterSizes = std::make_shared>(); + auto compClustersSizeGetter = [compClusterSizes](CompClusType const& compClusters, DataRef const& ref) { + auto const* dh = DataRefUtils::getHeader(ref); + (*compClusterSizes)[dh->subSpecification] = compClusters.size(); + }; + auto logger = [detName, compClusterSizes](std::vector const& rofs, DataRef const& ref) { + auto const* dh = DataRefUtils::getHeader(ref); + const auto i = dh->subSpecification; + LOG(info) << detName << "ClusterWriter:" << i << " pulled " << (*compClusterSizes)[i] << " clusters, in " << rofs.size() << " RO frames"; + }; + auto getIndex = [](DataRef const& ref) -> size_t { + auto const* dh = DataRefUtils::getHeader(ref); + return static_cast(dh->subSpecification); + }; + auto getName = [](std::string base, size_t index) -> std::string { + if constexpr (DPLAlpideParam::supportsStaggering()) { + return base += "_" + std::to_string(index); + } + return base; + }; + auto detNameLC = detName; + std::transform(detNameLC.begin(), detNameLC.end(), detNameLC.begin(), [](unsigned char c) { return std::tolower(c); }); + return MakeRootTreeWriterSpec(std::format("{}-cluster-writer", detNameLC).c_str(), + (o2::detectors::DetID::ITS == N) ? "o2clus_its.root" : "mftclusters.root", + MakeRootTreeWriterSpec::TreeAttributes{.name = "o2sim", .title = std::format("Tree with {} clusters", detName)}, + BranchDefinition{InputSpec{"compclus", ConcreteDataTypeMatcher{Origin, "COMPCLUSTERS"}}, + (detName + "ClusterComp").c_str(), "compact-cluster-branch", + NLayers, + compClustersSizeGetter, + getIndex, + getName}, + BranchDefinition{InputSpec{"patterns", ConcreteDataTypeMatcher{Origin, "PATTERNS"}}, + (detName + "ClusterPatt").c_str(), "cluster-pattern-branch", + NLayers, + getIndex, + getName}, + BranchDefinition{InputSpec{"ROframes", ConcreteDataTypeMatcher{Origin, "CLUSTERSROF"}}, + (detName + "ClustersROF").c_str(), "cluster-rof-branch", + NLayers, + logger, + getIndex, + getName}, + BranchDefinition{InputSpec{"labels", ConcreteDataTypeMatcher{Origin, "CLUSTERSMCTR"}}, + (detName + "ClusterMCTruth").c_str(), "cluster-label-branch", + (useMC ? NLayers : 0), + getIndex, + getName}, + BranchDefinition{InputSpec{"MC2ROframes", ConcreteDataTypeMatcher{Origin, "CLUSTERSMC2ROF"}}, + (detName + "ClustersMC2ROF").c_str(), "cluster-mc2rof-branch", + (useMC ? NLayers : 0), + getIndex, + getName})(); +} + +framework::DataProcessorSpec getITSClusterWriterSpec(bool useMC) { return getClusterWriterSpec(useMC); } +framework::DataProcessorSpec getMFTClusterWriterSpec(bool useMC) { return getClusterWriterSpec(useMC); } + +} // namespace o2::itsmft diff --git a/Detectors/ITSMFT/common/workflow/src/ClustererSpec.cxx b/Detectors/ITSMFT/common/workflow/src/ClustererSpec.cxx new file mode 100644 index 0000000000000..0b6bb44ee78c8 --- /dev/null +++ b/Detectors/ITSMFT/common/workflow/src/ClustererSpec.cxx @@ -0,0 +1,325 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file ClustererSpec.cxx + +#include + +#include "ITSMFTWorkflow/ClustererSpec.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/CCDBParamSpec.h" +#include "DataFormatsITSMFT/Digit.h" +#include "Framework/InputRecordWalker.h" +#include "ITSMFTReconstruction/ChipMappingMFT.h" +#include "ITSMFTReconstruction/ChipMappingITS.h" +#include "DataFormatsITSMFT/CompCluster.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/ConstMCTruthContainer.h" +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsParameters/GRPObject.h" +#include "ITSMFTReconstruction/DigitPixelReader.h" +#include "DetectorsBase/GeometryManager.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "CommonConstants/LHCConstants.h" +#include "DetectorsCommonDataFormats/DetectorNameConf.h" +#include "ITSMFTReconstruction/ClustererParam.h" + +namespace o2::itsmft +{ + +template +void ClustererDPL::init(InitContext& ic) +{ + mClusterer = std::make_unique(); + mClusterer->setNChips((N == o2::detectors::DetID::ITS) ? o2::itsmft::ChipMappingITS::getNChips() : o2::itsmft::ChipMappingMFT::getNChips()); + mUseClusterDictionary = !ic.options().get("ignore-cluster-dictionary"); + o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); + mNThreads = std::max(1, ic.options().get("nthreads")); + mDetName = Origin.as(); + + // prepare data filter + for (int iLayer = 0; iLayer < NLayers; ++iLayer) { + mFilter.emplace_back("digits", Origin, "DIGITS", iLayer, Lifetime::Timeframe); + mFilter.emplace_back("ROframe", Origin, "DIGITSROF", iLayer, Lifetime::Timeframe); + if (mUseMC) { + mFilter.emplace_back("labels", Origin, "DIGITSMCTR", iLayer, Lifetime::Timeframe); + mFilter.emplace_back("MC2ROframes", Origin, "DIGITSMC2ROF", iLayer, Lifetime::Timeframe); + } + } +} + +template +void ClustererDPL::run(ProcessingContext& pc) +{ + updateTimeDependentParams(pc); + + // filter input and compose + std::array, NLayers> digits; + std::array, NLayers> rofs; + std::array, NLayers> labelsbuffer; + std::array, NLayers> mc2rofs; + for (const DataRef& ref : InputRecordWalker{pc.inputs(), mFilter}) { + auto const* dh = DataRefUtils::getHeader(ref); + if (DataRefUtils::match(ref, {"digits", ConcreteDataTypeMatcher{Origin, "DIGITS"}})) { + digits[dh->subSpecification] = pc.inputs().get>(ref); + } + if (DataRefUtils::match(ref, {"ROframe", ConcreteDataTypeMatcher{Origin, "DIGITSROF"}})) { + rofs[dh->subSpecification] = pc.inputs().get>(ref); + } + if (DataRefUtils::match(ref, {"labels", ConcreteDataTypeMatcher{Origin, "DIGITSMCTR"}})) { + labelsbuffer[dh->subSpecification] = pc.inputs().get>(ref); + } + if (DataRefUtils::match(ref, {"MC2ROframes", ConcreteDataTypeMatcher{Origin, "DIGITSMC2ROF"}})) { + mc2rofs[dh->subSpecification] = pc.inputs().get>(ref); + } + } + + // query the first orbit in this TF + const auto firstTForbit = pc.services().get().firstTForbit; + const o2::InteractionRecord firstIR(0, firstTForbit); + const auto& par = DPLAlpideParam::Instance(); + + // process received inputs + uint64_t nClusters{0}; + TStopwatch sw; + o2::itsmft::DigitPixelReader reader; + for (uint32_t iLayer{0}; iLayer < NLayers; ++iLayer) { + int layer = (DPLAlpideParam::supportsStaggering()) ? iLayer : -1; + sw.Start(); + LOG(info) << mDetName << "Clusterer:" << layer << " pulled " << digits[iLayer].size() << " digits, in " << rofs[iLayer].size() << " RO frames"; + + mClusterer->setMaxROFDepthToSquash(mClusterer->getMaxROFDepthToSquash(layer)); + o2::dataformats::ConstMCTruthContainerView labels(labelsbuffer[iLayer]); + reader.setSquashingDepth(mClusterer->getMaxROFDepthToSquash(layer)); + reader.setSquashingDist(mClusterer->getMaxRowColDiffToMask()); // Sharing same parameter/logic with masking + reader.setMaxBCSeparationToSquash(mClusterer->getMaxBCSeparationToSquash(layer)); + reader.setDigits(digits[iLayer]); + reader.setROFRecords(rofs[iLayer]); + if (mUseMC) { + reader.setMC2ROFRecords(mc2rofs[iLayer]); + LOG(info) << mDetName << "Clusterer:" << layer << " pulled " << labels.getNElements() << " labels "; + reader.setDigitsMCTruth(labels.getIndexedSize() > 0 ? &labels : nullptr); + } + reader.init(); + std::vector clusCompVec; + std::vector clusROFVec; + std::vector clusPattVec; + + std::unique_ptr> clusterLabels; + if (mUseMC) { + clusterLabels = std::make_unique>(); + } + mClusterer->process(mNThreads, reader, &clusCompVec, &clusPattVec, &clusROFVec, clusterLabels.get()); + + // ensure that the rof output is continuous + size_t nROFs = clusROFVec.size(); + const int nROFsPerOrbit = o2::constants::lhc::LHCMaxBunches / par.getROFLengthInBC(iLayer); + const int nROFsTF = nROFsPerOrbit * o2::base::GRPGeomHelper::getNHBFPerTF(); + if (nROFsTF != clusROFVec.size()) { + // it can happen that in the digitization rofs without contributing hits are skipped + // however downstream consumers of the clusters cannot know apriori the time structure + // the cluster rofs do not account for the bias so it will start always at BC=0 + // if we receive more cluster rofs then there supposed to be, do not throw away this data + // the clusterer should be blind to this! + const size_t nROFsLayer = std::max((size_t)nROFsTF, clusROFVec.size()); + std::vector expClusRofVec(nROFsLayer); + for (int iROF{0}; iROF < nROFsLayer; ++iROF) { + auto& rof = expClusRofVec[iROF]; + int orb = iROF * par.getROFLengthInBC(iLayer) / o2::constants::lhc::LHCMaxBunches + firstTForbit; + int bc = iROF * par.getROFLengthInBC(iLayer) % o2::constants::lhc::LHCMaxBunches; + o2::InteractionRecord ir(bc, orb); + rof.setBCData(ir); + rof.setROFrame(iROF); + rof.setNEntries(0); + rof.setFirstEntry(-1); + } + uint32_t prevEntry{0}; + for (const auto& rof : clusROFVec) { + const auto& ir = rof.getBCData(); + const auto irToFirst = ir - firstIR; + const int irROF = irToFirst.toLong() / par.getROFLengthInBC(iLayer); + auto& expROF = expClusRofVec[irROF]; + expROF.setFirstEntry(rof.getFirstEntry()); + expROF.setNEntries(rof.getNEntries()); + if (expROF.getBCData() != rof.getBCData()) { + LOGP(fatal, "detected mismatch between expected ROF:{} and received ROF:{}", expROF.asString(), rof.asString()); + } + } + int prevFirst{0}; + for (auto& rof : expClusRofVec) { + if (rof.getFirstEntry() < 0) { + rof.setFirstEntry(prevFirst); + } + prevFirst = rof.getFirstEntry(); + } + nROFs = expClusRofVec.size(); + pc.outputs().snapshot(Output{Origin, "CLUSTERSROF", iLayer}, expClusRofVec); + } else { + pc.outputs().snapshot(Output{Origin, "CLUSTERSROF", iLayer}, clusROFVec); + } + pc.outputs().snapshot(Output{Origin, "COMPCLUSTERS", iLayer}, clusCompVec); + pc.outputs().snapshot(Output{Origin, "PATTERNS", iLayer}, clusPattVec); + + nClusters += clusCompVec.size(); + + if (mUseMC) { + pc.outputs().snapshot(Output{Origin, "CLUSTERSMCTR", iLayer}, *clusterLabels); // at the moment requires snapshot + std::vector clusterMC2ROframes(mc2rofs[iLayer].size()); + for (int i = mc2rofs[iLayer].size(); i--;) { + clusterMC2ROframes[i] = mc2rofs[iLayer][i]; // Simply, replicate it from digits ? + } + pc.outputs().snapshot(Output{Origin, "CLUSTERSMC2ROF", iLayer}, clusterMC2ROframes); + } + reader.reset(); + + // TODO: in principle, after masking "overflow" pixels the MC2ROFRecord maxROF supposed to change, nominally to minROF + // -> consider recalculationg maxROF + sw.Stop(); + LOG(info) << mDetName << "Clusterer:" << layer << " pushed " << clusCompVec.size() << " clusters, in " << nROFs << " RO frames in " << sw.RealTime() << " s"; + } + + LOG(info) << mDetName << "Clusterer produced " << nClusters << " clusters"; +} + +///_______________________________________ +template +void ClustererDPL::updateTimeDependentParams(ProcessingContext& pc) +{ + o2::base::GRPGeomHelper::instance().checkUpdates(pc); + static bool initOnceDone = false; + if (!initOnceDone) { // this params need to be queried only once + initOnceDone = true; + pc.inputs().get("cldict"); // just to trigger the finaliseCCDB + pc.inputs().get*>("alppar"); + pc.inputs().get*>("cluspar"); + mClusterer->setContinuousReadOut(o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(N)); + // settings for the fired pixel overflow masking + const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); + const auto& clParams = o2::itsmft::ClustererParam::Instance(); + if (clParams.maxBCDiffToMaskBias > 0 && clParams.maxBCDiffToSquashBias > 0) { + LOGP(fatal, "maxBCDiffToMaskBias = {} and maxBCDiffToSquashBias = {} cannot be set at the same time. Either set masking or squashing with a BCDiff > 0", clParams.maxBCDiffToMaskBias, clParams.maxBCDiffToSquashBias); + } + mClusterer->setDropHugeClusters(clParams.dropHugeClusters); + auto nbc = clParams.maxBCDiffToMaskBias; + nbc += mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); + mClusterer->setMaxBCSeparationToMask(nbc); + mClusterer->setMaxRowColDiffToMask(clParams.maxRowColDiffToMask); + // Squasher + int rofBC = mClusterer->isContinuousReadOut() ? alpParams.roFrameLengthInBC : (alpParams.roFrameLengthTrig / o2::constants::lhc::LHCBunchSpacingNS); // ROF length in BC + mClusterer->setMaxBCSeparationToSquash(rofBC + clParams.maxBCDiffToSquashBias); + int nROFsToSquash = 0; // squashing disabled if no reset due to maxSOTMUS>0. + if (clParams.maxSOTMUS > 0 && rofBC > 0) { + nROFsToSquash = 2 + int(clParams.maxSOTMUS / (rofBC * o2::constants::lhc::LHCBunchSpacingMUS)); // use squashing + } + mClusterer->setMaxROFDepthToSquash(nROFsToSquash); + if constexpr (DPLAlpideParam::supportsStaggering()) { + if (mClusterer->isContinuousReadOut()) { + for (int iLayer{0}; iLayer < NLayers; ++iLayer) { + mClusterer->addMaxBCSeparationToSquash(alpParams.getROFLengthInBC(iLayer) + clParams.getMaxBCDiffToSquashBias(iLayer)); + mClusterer->addMaxROFDepthToSquash((clParams.getMaxBCDiffToSquashBias(iLayer) > 0) ? 2 + int(clParams.maxSOTMUS / (alpParams.getROFLengthInBC(iLayer) * o2::constants::lhc::LHCBunchSpacingMUS)) : 0); + } + } + } + mClusterer->print(false); + } + // we may have other params which need to be queried regularly +} + +///_______________________________________ +template +void ClustererDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) +{ + if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { + return; + } + if (matcher == ConcreteDataMatcher(Origin, "CLUSDICT", 0)) { + LOG(info) << "cluster dictionary updated" << (!mUseClusterDictionary ? " but its using is disabled" : ""); + if (mUseClusterDictionary) { + mClusterer->setDictionary((const TopologyDictionary*)obj); + } + return; + } + // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level + if (matcher == ConcreteDataMatcher(Origin, "ALPIDEPARAM", 0)) { + LOG(info) << "Alpide param updated"; + const auto& par = o2::itsmft::DPLAlpideParam::Instance(); + par.printKeyValues(); + return; + } + if (matcher == ConcreteDataMatcher(Origin, "CLUSPARAM", 0)) { + LOG(info) << "Cluster param updated"; + const auto& par = o2::itsmft::ClustererParam::Instance(); + par.printKeyValues(); + return; + } +} + +namespace +{ +template +DataProcessorSpec getClustererSpec(bool useMC) +{ + constexpr o2::header::DataOrigin Origin{N == o2::detectors::DetID::ITS ? o2::header::gDataOriginITS : o2::header::gDataOriginMFT}; + std::vector inputs; + constexpr uint32_t nLayers = (DPLAlpideParam::supportsStaggering()) ? DPLAlpideParam::getNLayers() : 1; + for (uint32_t iLayer = 0; iLayer < nLayers; ++iLayer) { + inputs.emplace_back("digits", Origin, "DIGITS", iLayer, Lifetime::Timeframe); + inputs.emplace_back("ROframes", Origin, "DIGITSROF", iLayer, Lifetime::Timeframe); + if (useMC) { + inputs.emplace_back("labels", Origin, "DIGITSMCTR", iLayer, Lifetime::Timeframe); + inputs.emplace_back("MC2ROframes", Origin, "DIGITSMC2ROF", iLayer, Lifetime::Timeframe); + } + } + inputs.emplace_back("cldict", Origin, "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec(Origin.as() + "/Calib/ClusterDictionary")); + inputs.emplace_back("cluspar", Origin, "CLUSPARAM", 0, Lifetime::Condition, ccdbParamSpec(Origin.as() + "/Config/ClustererParam")); + inputs.emplace_back("alppar", Origin, "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec(Origin.as() + "/Config/AlpideParam")); + auto ggRequest = std::make_shared(false, // orbitResetTime + true, // GRPECS=true + false, // GRPLHCIF + false, // GRPMagField + false, // askMatLUT + o2::base::GRPGeomRequest::None, // geometry + inputs, + true); + std::vector outputs; + for (uint32_t iLayer = 0; iLayer < nLayers; ++iLayer) { + outputs.emplace_back(Origin, "COMPCLUSTERS", iLayer, Lifetime::Timeframe); + outputs.emplace_back(Origin, "PATTERNS", iLayer, Lifetime::Timeframe); + outputs.emplace_back(Origin, "CLUSTERSROF", iLayer, Lifetime::Timeframe); + if (useMC) { + outputs.emplace_back(Origin, "CLUSTERSMCTR", iLayer, Lifetime::Timeframe); + outputs.emplace_back(Origin, "CLUSTERSMC2ROF", iLayer, Lifetime::Timeframe); + } + } + return DataProcessorSpec{ + .name = (N == o2::detectors::DetID::ITS) ? "its-clusterer" : "mft-clusterer", + .inputs = inputs, + .outputs = outputs, + .algorithm = AlgorithmSpec{adaptFromTask>(ggRequest, useMC)}, + .options = Options{ + {"ignore-cluster-dictionary", VariantType::Bool, false, {"do not use cluster dictionary, always store explicit patterns"}}, + {"nthreads", VariantType::Int, 1, {"Number of clustering threads"}}}}; +} +} // namespace + +framework::DataProcessorSpec getITSClustererSpec(bool useMC) +{ + return getClustererSpec(useMC); +} + +framework::DataProcessorSpec getMFTClustererSpec(bool useMC) +{ + return getClustererSpec(useMC); +} + +} // namespace o2::itsmft diff --git a/Detectors/Upgrades/ITS3/workflow/src/RecoWorkflow.cxx b/Detectors/Upgrades/ITS3/workflow/src/RecoWorkflow.cxx index 004c3f6097167..60fe4fabfe481 100644 --- a/Detectors/Upgrades/ITS3/workflow/src/RecoWorkflow.cxx +++ b/Detectors/Upgrades/ITS3/workflow/src/RecoWorkflow.cxx @@ -12,7 +12,7 @@ #include "ITS3Workflow/RecoWorkflow.h" #include "ITS3Workflow/ClustererSpec.h" #include "ITS3Workflow/TrackerSpec.h" -#include "ITSWorkflow/ClusterWriterSpec.h" +#include "ITSMFTWorkflow/ClusterWriterSpec.h" #include "ITSWorkflow/TrackWriterSpec.h" #include "ITS3Workflow/DigitReaderSpec.h" #include "GPUWorkflow/GPUWorkflowSpec.h" @@ -40,7 +40,7 @@ framework::WorkflowSpec getWorkflow(bool useMC, its::TrackingMode::Type trmode, } if (!disableRootOutput) { - specs.emplace_back(o2::its::getClusterWriterSpec(useMC)); + specs.emplace_back(o2::itsmft::getITSClusterWriterSpec(useMC)); } if (trmode != its::TrackingMode::Off) { From 4ec73c1134146fdf5648327c62d112625240f3c3 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Thu, 12 Feb 2026 13:32:13 +0100 Subject: [PATCH 196/234] DPL: introduce range based views to navigate data model (#15061) --- .../Core/include/Framework/DataModelViews.h | 239 ++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 Framework/Core/include/Framework/DataModelViews.h diff --git a/Framework/Core/include/Framework/DataModelViews.h b/Framework/Core/include/Framework/DataModelViews.h new file mode 100644 index 0000000000000..b7a334454bb6e --- /dev/null +++ b/Framework/Core/include/Framework/DataModelViews.h @@ -0,0 +1,239 @@ +// Copyright 2019-2025 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_DATASPECVIEWS_H_ +#define O2_FRAMEWORK_DATASPECVIEWS_H_ + +#include +#include +#include "DomainInfoHeader.h" +#include "SourceInfoHeader.h" +#include "Headers/DataHeader.h" +#include + +namespace o2::framework +{ + +struct count_payloads { + // ends the pipeline, returns the container + template + requires std::ranges::random_access_range && std::ranges::sized_range + friend size_t operator|(R&& r, count_payloads self) + { + size_t count = 0; + size_t mi = 0; + while (mi < r.size()) { + auto* header = o2::header::get(r[mi]->GetData()); + if (!header) { + throw std::runtime_error("Not a DataHeader"); + } + if (header->splitPayloadParts > 1 && header->splitPayloadIndex == header->splitPayloadParts) { + count += header->splitPayloadParts; + mi += header->splitPayloadParts + 1; + } else { + count += header->splitPayloadParts ? header->splitPayloadParts : 1; + mi += header->splitPayloadParts ? 2 * header->splitPayloadParts : 2; + } + } + return count; + } +}; + +struct count_parts { + // ends the pipeline, returns the number of parts + template + requires std::ranges::random_access_range && std::ranges::sized_range + friend size_t operator|(R&& r, count_parts self) + { + size_t count = 0; + size_t mi = 0; + while (mi < r.size()) { + auto* header = o2::header::get(r[mi]->GetData()); + auto* sih = o2::header::get(r[mi]->GetData()); + auto* dih = o2::header::get(r[mi]->GetData()); + if (!header && !sih && !dih) { + throw std::runtime_error("Header information not found"); + } + // We skip oldest possible timeframe / end of stream and not consider it + // as actual parts. + if (dih || sih) { + count += 1; + mi += 2; + } else if (header->splitPayloadParts > 1 && header->splitPayloadIndex == header->splitPayloadParts) { + count += 1; + mi += header->splitPayloadParts + 1; + } else { + count += header->splitPayloadParts; + mi += header->splitPayloadParts ? 2 * header->splitPayloadParts : 2; + } + } + return count; + } +}; + +struct DataRefIndices { + size_t headerIdx; + size_t payloadIdx; +}; + +struct get_pair { + size_t pairId; + template + requires std::ranges::random_access_range && std::ranges::sized_range + friend DataRefIndices operator|(R&& r, get_pair self) + { + size_t count = 0; + size_t mi = 0; + while (mi < r.size()) { + auto* header = o2::header::get(r[mi]->GetData()); + if (!header) { + throw std::runtime_error("Not a DataHeader"); + } + size_t diff = self.pairId - count; + if (header->splitPayloadParts > 1 && header->splitPayloadIndex == header->splitPayloadParts) { + count += header->splitPayloadParts; + if (self.pairId < count) { + return {mi, mi + 1 + diff}; + } + mi += header->splitPayloadParts + 1; + } else { + count += header->splitPayloadParts ? header->splitPayloadParts : 1; + if (self.pairId < count) { + return {mi, mi + 2 * diff + 1}; + } + mi += header->splitPayloadParts ? 2 * header->splitPayloadParts : 2; + } + } + throw std::runtime_error("Payload not found"); + } +}; + +struct get_dataref_indices { + size_t part; + size_t subPart; + // ends the pipeline, returns the number of parts + template + requires std::ranges::random_access_range && std::ranges::sized_range + friend DataRefIndices operator|(R&& r, get_dataref_indices self) + { + size_t count = 0; + size_t mi = 0; + while (mi < r.size()) { + auto* header = o2::header::get(r[mi]->GetData()); + if (!header) { + throw std::runtime_error("Not a DataHeader"); + } + if (header->splitPayloadParts > 1 && header->splitPayloadIndex == header->splitPayloadParts) { + if (self.part == count) { + return {mi, mi + 1 + self.subPart}; + } + count += 1; + mi += header->splitPayloadParts + 1; + } else { + if (self.part == count) { + return {mi, mi + 2 * self.subPart + 1}; + } + count += 1; + mi += header->splitPayloadParts ? 2 * header->splitPayloadParts : 2; + } + } + throw std::runtime_error("Payload not found"); + } +}; + +struct get_header { + size_t id; + // ends the pipeline, returns the number of parts + template + requires std::ranges::random_access_range && std::ranges::sized_range + friend fair::mq::MessagePtr& operator|(R&& r, get_header self) + { + return r[(r | get_dataref_indices{self.id, 0}).headerIdx]; + } +}; + +struct get_payload { + size_t part; + size_t subPart; + // ends the pipeline, returns the number of parts + template + requires std::ranges::random_access_range && std::ranges::sized_range + friend fair::mq::MessagePtr& operator|(R&& r, get_payload self) + { + return r[(r | get_dataref_indices{self.part, self.subPart}).payloadIdx]; + } +}; + +struct get_num_payloads { + size_t id; + // ends the pipeline, returns the number of parts + template + requires std::ranges::random_access_range && std::ranges::sized_range + friend size_t operator|(R&& r, get_num_payloads self) + { + size_t count = 0; + size_t mi = 0; + while (mi < r.size()) { + auto* header = o2::header::get(r[mi]->GetData()); + if (!header) { + throw std::runtime_error("Not a DataHeader"); + } + if (self.id == count) { + if (header->splitPayloadParts > 1 && (header->splitPayloadIndex == header->splitPayloadParts)) { + return header->splitPayloadParts; + } else { + return 1; + } + } + if (header->splitPayloadParts > 1 && (header->splitPayloadIndex == header->splitPayloadParts)) { + count += 1; + mi += header->splitPayloadParts + 1; + } else { + count += 1; + mi += header->splitPayloadParts ? 2 * header->splitPayloadParts : 2; + } + } + return 0; + } +}; + +struct MessageSet; + +struct MessageStore { + std::span sets; + size_t inputsPerSlot = 0; +}; + +struct inputs_for_slot { + TimesliceSlot slot; + template + requires requires(R r) { std::ranges::random_access_range; } + friend std::span operator|(R&& r, inputs_for_slot self) + { + return std::span(r.sets[self.slot.index * r.inputsPerSlot]); + } +}; + +struct messages_for_input { + size_t inputIdx; + template + requires std::ranges::random_access_range + friend std::span operator|(R&& r, messages_for_input self) + { + return r[self.inputIdx].messages; + } +}; + +// FIXME: we should use special index classes in place of size_t +// FIXME: we need something to substitute a range in the store with another + +} // namespace o2::framework + +#endif // O2_FRAMEWORK_DATASPECVIEWS_H_ From 834cbc5b6f9e0f73b4bdedbb96df73538571571f Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 12 Feb 2026 14:39:27 +0100 Subject: [PATCH 197/234] FST: Make previousOrbit configurable --- prodtests/full_system_test.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/prodtests/full_system_test.sh b/prodtests/full_system_test.sh index e2ecca590140f..82021d6c65e63 100755 --- a/prodtests/full_system_test.sh +++ b/prodtests/full_system_test.sh @@ -40,6 +40,7 @@ export LC_ALL=C BEAMTYPE=${BEAMTYPE:-PbPb} NEvents=${NEvents:-10} #550 for full TF (the number of PbPb events) NEventsQED=${NEventsQED:-1000} #35000 for full TF +OrbitsBeforeTf=${OrbitsBeforeTf:-1} NCPUS=$(getNumberOfPhysicalCPUCores) echo "Found ${NCPUS} physical CPU cores" NJOBS=${NJOBS:-"${NCPUS}"} @@ -159,7 +160,7 @@ taskwrapper collcontext.log o2-steer-colcontexttool \ --extract-per-timeframe tf:o2sim \ --with-vertices kCCDB \ --maxCollsPerTF ${NEvents} \ - --orbitsEarly 1 \ + --orbitsEarly ${OrbitsBeforeTf} \ --bcPatternFile ccdb \ ${QEDSPEC} From 23765b5bdef76fb5a3151d01df8f908936aacf94 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 13 Feb 2026 09:03:17 +0100 Subject: [PATCH 198/234] DPL: Enforce that dpl pipeline length is at least as long as number of TFs in flight (#15048) --- .../Core/include/Framework/DataRelayer.h | 3 ++- .../Core/include/Framework/DefaultsHelpers.h | 10 +++++++- Framework/Core/src/ArrowSupport.cxx | 2 +- Framework/Core/src/CommonServices.cxx | 4 +++- Framework/Core/src/DataProcessingDevice.cxx | 12 ++++++---- Framework/Core/src/DataRelayer.cxx | 17 ++++++++++++-- Framework/Core/src/DefaultsHelpers.cxx | 23 +++++++++++++++---- Framework/Core/src/runDataProcessing.cxx | 5 ++-- Framework/Core/test/benchmark_DataRelayer.cxx | 10 ++++---- Framework/Core/test/test_DataRelayer.cxx | 22 +++++++++--------- 10 files changed, 75 insertions(+), 33 deletions(-) diff --git a/Framework/Core/include/Framework/DataRelayer.h b/Framework/Core/include/Framework/DataRelayer.h index 1e010fc12f3d4..e5a2aecea1de4 100644 --- a/Framework/Core/include/Framework/DataRelayer.h +++ b/Framework/Core/include/Framework/DataRelayer.h @@ -102,7 +102,8 @@ class DataRelayer DataRelayer(CompletionPolicy const&, std::vector const& routes, TimesliceIndex&, - ServiceRegistryRef); + ServiceRegistryRef, + int); /// This invokes the appropriate `InputRoute::danglingChecker` on every /// entry in the cache and if it returns true, it creates a new diff --git a/Framework/Core/include/Framework/DefaultsHelpers.h b/Framework/Core/include/Framework/DefaultsHelpers.h index 16d41d03baa7f..68e64cc42a90e 100644 --- a/Framework/Core/include/Framework/DefaultsHelpers.h +++ b/Framework/Core/include/Framework/DefaultsHelpers.h @@ -12,16 +12,24 @@ #ifndef O2_FRAMEWORK_DEFAULTHELPERS_H_ #define O2_FRAMEWORK_DEFAULTHELPERS_H_ +namespace fair::mq +{ +class ProgOptions; +} + namespace o2::framework { enum struct DeploymentMode; +struct DeviceConfig; struct DefaultsHelpers { static DeploymentMode deploymentMode(); /// @true if running online static bool onlineDeploymentMode(); /// get max number of timeslices in the queue - static unsigned int pipelineLength(); + static unsigned int pipelineLength(unsigned int minLength); + static unsigned int pipelineLength(const fair::mq::ProgOptions& options); + static unsigned int pipelineLength(const DeviceConfig& dc); }; } // namespace o2::framework diff --git a/Framework/Core/src/ArrowSupport.cxx b/Framework/Core/src/ArrowSupport.cxx index 450f31f4ba7d3..c5cc021a53478 100644 --- a/Framework/Core/src/ArrowSupport.cxx +++ b/Framework/Core/src/ArrowSupport.cxx @@ -564,7 +564,7 @@ o2::framework::ServiceSpec ArrowSupport::arrowBackendSpec() if (dc.options.count("timeframes-rate-limit") && dc.options["timeframes-rate-limit"].defaulted() == false) { config->maxTimeframes = std::stoll(dc.options["timeframes-rate-limit"].as()); } else { - config->maxTimeframes = readers * DefaultsHelpers::pipelineLength(); + config->maxTimeframes = readers * DefaultsHelpers::pipelineLength(dc); } static bool once = false; // Until we guarantee this is called only once... diff --git a/Framework/Core/src/CommonServices.cxx b/Framework/Core/src/CommonServices.cxx index f786d99fd2c0d..6486406a06dca 100644 --- a/Framework/Core/src/CommonServices.cxx +++ b/Framework/Core/src/CommonServices.cxx @@ -414,11 +414,13 @@ o2::framework::ServiceSpec CommonServices::dataRelayer() .name = "datarelayer", .init = [](ServiceRegistryRef services, DeviceState&, fair::mq::ProgOptions& options) -> ServiceHandle { auto& spec = services.get(); + int pipelineLength = DefaultsHelpers::pipelineLength(options); return ServiceHandle{TypeIdHelpers::uniqueId(), new DataRelayer(spec.completionPolicy, spec.inputs, services.get(), - services)}; + services, + pipelineLength)}; }, .configure = noConfiguration(), .kind = ServiceKind::Serial}; diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index ccfb58db7559a..da04a23e81c0c 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -1483,7 +1483,7 @@ void DataProcessingDevice::doPrepare(ServiceRegistryRef ref) auto& infos = state.inputChannelInfos; if (context.balancingInputs) { - static int pipelineLength = DefaultsHelpers::pipelineLength(); + static int pipelineLength = DefaultsHelpers::pipelineLength(*ref.get().device()->fConfig); static uint64_t ahead = getenv("DPL_MAX_CHANNEL_AHEAD") ? std::atoll(getenv("DPL_MAX_CHANNEL_AHEAD")) : std::max(8, std::min(pipelineLength - 48, pipelineLength / 2)); auto newEnd = std::remove_if(pollOrder.begin(), pollOrder.end(), [&infos, limitNew = currentOldest.value + ahead](int a) -> bool { return infos[a].oldestForChannel.value > limitNew; @@ -2259,12 +2259,14 @@ bool DataProcessingDevice::tryDispatchComputation(ServiceRegistryRef ref, std::v return false; } - auto postUpdateStats = [ref](DataRelayer::RecordAction const& action, InputRecord const& record, uint64_t tStart, uint64_t tStartMilli) { + int pipelineLength = DefaultsHelpers::pipelineLength(*ref.get().device()->fConfig); + + auto postUpdateStats = [ref, pipelineLength](DataRelayer::RecordAction const& action, InputRecord const& record, uint64_t tStart, uint64_t tStartMilli) { auto& stats = ref.get(); auto& states = ref.get(); std::atomic_thread_fence(std::memory_order_release); char relayerSlotState[1024]; - int written = snprintf(relayerSlotState, 1024, "%d ", DefaultsHelpers::pipelineLength()); + int written = snprintf(relayerSlotState, 1024, "%d ", pipelineLength); char* buffer = relayerSlotState + written; for (size_t ai = 0; ai != record.size(); ai++) { buffer[ai] = record.isValid(ai) ? '3' : '0'; @@ -2291,11 +2293,11 @@ bool DataProcessingDevice::tryDispatchComputation(ServiceRegistryRef ref, std::v count++; }; - auto preUpdateStats = [ref](DataRelayer::RecordAction const& action, InputRecord const& record, uint64_t) { + auto preUpdateStats = [ref, pipelineLength](DataRelayer::RecordAction const& action, InputRecord const& record, uint64_t) { auto& states = ref.get(); std::atomic_thread_fence(std::memory_order_release); char relayerSlotState[1024]; - snprintf(relayerSlotState, 1024, "%d ", DefaultsHelpers::pipelineLength()); + snprintf(relayerSlotState, 1024, "%d ", pipelineLength); char* buffer = strchr(relayerSlotState, ' ') + 1; for (size_t ai = 0; ai != record.size(); ai++) { buffer[ai] = record.isValid(ai) ? '2' : '0'; diff --git a/Framework/Core/src/DataRelayer.cxx b/Framework/Core/src/DataRelayer.cxx index 05b64b6ed1dad..cece5b343659f 100644 --- a/Framework/Core/src/DataRelayer.cxx +++ b/Framework/Core/src/DataRelayer.cxx @@ -37,6 +37,7 @@ #include "Framework/DataProcessingStates.h" #include "Framework/DataTakingContext.h" #include "Framework/DefaultsHelpers.h" +#include "Framework/RawDeviceService.h" #include "Headers/DataHeaderHelpers.h" #include "Framework/Formatters.h" @@ -48,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -70,7 +72,8 @@ constexpr int INVALID_INPUT = -1; DataRelayer::DataRelayer(const CompletionPolicy& policy, std::vector const& routes, TimesliceIndex& index, - ServiceRegistryRef services) + ServiceRegistryRef services, + int pipelineLength) : mContext{services}, mTimesliceIndex{index}, mCompletionPolicy{policy}, @@ -81,7 +84,17 @@ DataRelayer::DataRelayer(const CompletionPolicy& policy, std::scoped_lock lock(mMutex); if (policy.configureRelayer == nullptr) { - static int pipelineLength = DefaultsHelpers::pipelineLength(); + if (pipelineLength == -1) { + auto getPipelineLengthHelper = [&services]() { + try { + return DefaultsHelpers::pipelineLength(*services.get().device()->fConfig); + } catch (...) { + return DefaultsHelpers::pipelineLength(0); + } + }; + static int detectedPipelineLength = getPipelineLengthHelper(); + pipelineLength = detectedPipelineLength; + } setPipelineLength(pipelineLength); } else { policy.configureRelayer(*this); diff --git a/Framework/Core/src/DefaultsHelpers.cxx b/Framework/Core/src/DefaultsHelpers.cxx index 4dcc734216f0c..5fd1ed29e7af6 100644 --- a/Framework/Core/src/DefaultsHelpers.cxx +++ b/Framework/Core/src/DefaultsHelpers.cxx @@ -11,6 +11,9 @@ #include "Framework/DefaultsHelpers.h" #include "Framework/DataTakingContext.h" +#include "Framework/DeviceConfig.h" +#include + #include #include #include @@ -18,23 +21,35 @@ namespace o2::framework { -unsigned int DefaultsHelpers::pipelineLength() +unsigned int DefaultsHelpers::pipelineLength(unsigned int minLength) { static bool override = getenv("DPL_DEFAULT_PIPELINE_LENGTH"); if (override) { static unsigned int retval = atoi(getenv("DPL_DEFAULT_PIPELINE_LENGTH")); - return retval; + return std::max(minLength, retval); } DeploymentMode deploymentMode = DefaultsHelpers::deploymentMode(); // just some reasonable numers // The number should really be tuned at runtime for each processor. if (deploymentMode == DeploymentMode::OnlineDDS || deploymentMode == DeploymentMode::OnlineECS || deploymentMode == DeploymentMode::FST) { - return 512; + return std::max(minLength, 512u); } else { - return 64; + return std::max(minLength, 64u); } } +unsigned int DefaultsHelpers::pipelineLength(const DeviceConfig& dc) +{ + static unsigned int minLength = dc.options.count("timeframes-rate-limit") ? std::max(0, atoi(dc.options["timeframes-rate-limit"].as().c_str())) : 0; + return pipelineLength(minLength); +} + +unsigned int DefaultsHelpers::pipelineLength(const fair::mq::ProgOptions& options) +{ + static unsigned int minLength = options.Count("timeframes-rate-limit") ? std::max(0, atoi(options.GetValue("timeframes-rate-limit").c_str())) : 0; + return pipelineLength(minLength); +} + static DeploymentMode getDeploymentMode_internal() { char* explicitMode = getenv("O2_DPL_DEPLOYMENT_MODE"); diff --git a/Framework/Core/src/runDataProcessing.cxx b/Framework/Core/src/runDataProcessing.cxx index 166f26878c363..ced884ebaa1ed 100644 --- a/Framework/Core/src/runDataProcessing.cxx +++ b/Framework/Core/src/runDataProcessing.cxx @@ -817,7 +817,8 @@ void spawnDevice(uv_loop_t* loop, .sendInitialValue = true, }); - for (size_t i = 0; i < DefaultsHelpers::pipelineLength(); ++i) { + unsigned int pipelineLength = DefaultsHelpers::pipelineLength(DeviceConfig{varmap}); + for (size_t i = 0; i < pipelineLength; ++i) { allStates.back().registerState(DataProcessingStates::StateSpec{ .name = fmt::format("matcher_variables/{}", i), .stateId = static_cast((short)(ProcessingStateId::CONTEXT_VARIABLES_BASE) + i), @@ -826,7 +827,7 @@ void spawnDevice(uv_loop_t* loop, }); } - for (size_t i = 0; i < DefaultsHelpers::pipelineLength(); ++i) { + for (size_t i = 0; i < pipelineLength; ++i) { allStates.back().registerState(DataProcessingStates::StateSpec{ .name = fmt::format("data_relayer/{}", i), .stateId = static_cast((short)(ProcessingStateId::DATA_RELAYER_BASE) + i), diff --git a/Framework/Core/test/benchmark_DataRelayer.cxx b/Framework/Core/test/benchmark_DataRelayer.cxx index dcff3930dbaad..3c3d2294fdd7e 100644 --- a/Framework/Core/test/benchmark_DataRelayer.cxx +++ b/Framework/Core/test/benchmark_DataRelayer.cxx @@ -65,7 +65,7 @@ static void BM_RelaySingleSlot(benchmark::State& state) TimesliceIndex index{1, infos}; auto policy = CompletionPolicyHelpers::consumeWhenAny(); ServiceRegistry registry; - DataRelayer relayer(policy, inputs, index, {registry}); + DataRelayer relayer(policy, inputs, index, {registry}, -1); relayer.setPipelineLength(4); // Let's create a dummy O2 Message with two headers in the stack: @@ -118,7 +118,7 @@ static void BM_RelayMultipleSlots(benchmark::State& state) auto policy = CompletionPolicyHelpers::consumeWhenAny(); ServiceRegistry registry; - DataRelayer relayer(policy, inputs, index, {registry}); + DataRelayer relayer(policy, inputs, index, {registry}, -1); relayer.setPipelineLength(4); // Let's create a dummy O2 Message with two headers in the stack: @@ -177,7 +177,7 @@ static void BM_RelayMultipleRoutes(benchmark::State& state) auto policy = CompletionPolicyHelpers::consumeWhenAny(); ServiceRegistry registry; - DataRelayer relayer(policy, inputs, index, {registry}); + DataRelayer relayer(policy, inputs, index, {registry}, -1); relayer.setPipelineLength(4); // Let's create a dummy O2 Message with two headers in the stack: @@ -254,7 +254,7 @@ static void BM_RelaySplitParts(benchmark::State& state) auto policy = CompletionPolicyHelpers::consumeWhenAny(); ServiceRegistry registry; - DataRelayer relayer(policy, inputs, index, {registry}); + DataRelayer relayer(policy, inputs, index, {registry}, -1); relayer.setPipelineLength(4); // Let's create a dummy O2 Message with two headers in the stack: @@ -314,7 +314,7 @@ static void BM_RelayMultiplePayloads(benchmark::State& state) auto policy = CompletionPolicyHelpers::consumeWhenAny(); ServiceRegistry registry; - DataRelayer relayer(policy, inputs, index, {registry}); + DataRelayer relayer(policy, inputs, index, {registry}, -1); relayer.setPipelineLength(4); // DataHeader matching the one provided in the input diff --git a/Framework/Core/test/test_DataRelayer.cxx b/Framework/Core/test/test_DataRelayer.cxx index 7d5a3ded88e16..8957e361cb8a2 100644 --- a/Framework/Core/test/test_DataRelayer.cxx +++ b/Framework/Core/test/test_DataRelayer.cxx @@ -83,7 +83,7 @@ TEST_CASE("DataRelayer") ref.registerService(ServiceRegistryHelpers::handleForService(&index)); auto policy = CompletionPolicyHelpers::consumeWhenAny(); - DataRelayer relayer(policy, inputs, index, {registry}); + DataRelayer relayer(policy, inputs, index, {registry}, -1); relayer.setPipelineLength(4); // Let's create a dummy O2 Message with two headers in the stack: @@ -133,7 +133,7 @@ TEST_CASE("DataRelayer") ref.registerService(ServiceRegistryHelpers::handleForService(&index)); auto policy = CompletionPolicyHelpers::consumeWhenAny(); - DataRelayer relayer(policy, inputs, index, {registry}); + DataRelayer relayer(policy, inputs, index, {registry}, -1); relayer.setPipelineLength(4); // Let's create a dummy O2 Message with two headers in the stack: @@ -195,7 +195,7 @@ TEST_CASE("DataRelayer") ref.registerService(ServiceRegistryHelpers::handleForService(&index)); auto policy = CompletionPolicyHelpers::consumeWhenAll(); - DataRelayer relayer(policy, inputs, index, {registry}); + DataRelayer relayer(policy, inputs, index, {registry}, -1); relayer.setPipelineLength(4); auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq"); @@ -276,7 +276,7 @@ TEST_CASE("DataRelayer") ref.registerService(ServiceRegistryHelpers::handleForService(&index)); auto policy = CompletionPolicyHelpers::consumeWhenAll(); - DataRelayer relayer(policy, inputs, index, {registry}); + DataRelayer relayer(policy, inputs, index, {registry}, -1); relayer.setPipelineLength(3); auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq"); @@ -359,7 +359,7 @@ TEST_CASE("DataRelayer") std::vector infos{1}; TimesliceIndex index{1, infos}; ref.registerService(ServiceRegistryHelpers::handleForService(&index)); - DataRelayer relayer(policy, inputs, index, {registry}); + DataRelayer relayer(policy, inputs, index, {registry}, -1); // Only two messages to fill the cache. relayer.setPipelineLength(2); @@ -437,7 +437,7 @@ TEST_CASE("DataRelayer") ref.registerService(ServiceRegistryHelpers::handleForService(&index)); auto policy = CompletionPolicyHelpers::processWhenAny(); - DataRelayer relayer(policy, inputs, index, {registry}); + DataRelayer relayer(policy, inputs, index, {registry}, -1); // Only two messages to fill the cache. relayer.setPipelineLength(2); @@ -509,7 +509,7 @@ TEST_CASE("DataRelayer") ref.registerService(ServiceRegistryHelpers::handleForService(&index)); auto policy = CompletionPolicyHelpers::processWhenAny(); - DataRelayer relayer(policy, inputs, index, {registry}); + DataRelayer relayer(policy, inputs, index, {registry}, -1); // Only two messages to fill the cache. relayer.setPipelineLength(3); @@ -568,7 +568,7 @@ TEST_CASE("DataRelayer") ref.registerService(ServiceRegistryHelpers::handleForService(&index)); auto policy = CompletionPolicyHelpers::processWhenAny(); - DataRelayer relayer(policy, inputs, index, {registry}); + DataRelayer relayer(policy, inputs, index, {registry}, -1); // Only two messages to fill the cache. relayer.setPipelineLength(1); @@ -629,7 +629,7 @@ TEST_CASE("DataRelayer") ref.registerService(ServiceRegistryHelpers::handleForService(&index)); auto policy = CompletionPolicyHelpers::processWhenAny(); - DataRelayer relayer(policy, inputs, index, {registry}); + DataRelayer relayer(policy, inputs, index, {registry}, -1); // Only two messages to fill the cache. relayer.setPipelineLength(1); @@ -698,7 +698,7 @@ TEST_CASE("DataRelayer") ref.registerService(ServiceRegistryHelpers::handleForService(&index)); auto policy = CompletionPolicyHelpers::consumeWhenAny(); - DataRelayer relayer(policy, inputs, index, {registry}); + DataRelayer relayer(policy, inputs, index, {registry}, -1); relayer.setPipelineLength(4); DataHeader dh{"CLUSTERS", "TPC", 0}; @@ -752,7 +752,7 @@ TEST_CASE("DataRelayer") ref.registerService(ServiceRegistryHelpers::handleForService(&index)); auto policy = CompletionPolicyHelpers::consumeWhenAny(); - DataRelayer relayer(policy, inputs, index, {registry}); + DataRelayer relayer(policy, inputs, index, {registry}, -1); relayer.setPipelineLength(4); auto transport = fair::mq::TransportFactory::CreateTransportFactory("zeromq"); From ab29595c9106a6f5c28bc1a12cb0402cb7f446b8 Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Fri, 13 Feb 2026 10:47:40 +0100 Subject: [PATCH 199/234] Update examples on AO2D creation from MCTracks (#15056) --- run/SimExamples/HepMC_STARlight/run_HepMCToAOD.sh | 2 +- run/SimExamples/McTracksToAOD/run_O2Kine.sh | 5 +++-- run/SimExamples/McTracksToAOD/run_Pythia8.sh | 2 +- run/SimExamples/McTracksToAOD/run_trigger.sh | 6 +++--- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/run/SimExamples/HepMC_STARlight/run_HepMCToAOD.sh b/run/SimExamples/HepMC_STARlight/run_HepMCToAOD.sh index f08de81b92d8c..7671d03b97b8f 100755 --- a/run/SimExamples/HepMC_STARlight/run_HepMCToAOD.sh +++ b/run/SimExamples/HepMC_STARlight/run_HepMCToAOD.sh @@ -18,7 +18,7 @@ set -x # PART b) ... apply vertex smearing on top of HepMC events and perform simple analysis NEV=$(grep EVENT slight.out | wc -l) -o2-sim-dpl-eventgen -b --nevents ${NEV} --generator hepmc --confKeyValues \ +o2-sim-dpl-eventgen -b --nEvents ${NEV} --generator hepmc --configKeyValues \ "GeneratorFileOrCmd.fileNames=starlight.hepmc;Diamond.position[2]=0.1;Diamond.width[2]=0.05" |\ o2-sim-mctracks-to-aod -b | o2-analysis-mctracks-to-aod-simple-task -b diff --git a/run/SimExamples/McTracksToAOD/run_O2Kine.sh b/run/SimExamples/McTracksToAOD/run_O2Kine.sh index 7506f00834fcf..9afac20cd1a0b 100755 --- a/run/SimExamples/McTracksToAOD/run_O2Kine.sh +++ b/run/SimExamples/McTracksToAOD/run_O2Kine.sh @@ -10,6 +10,7 @@ NEVENTS=1000 # launch generator process (for 10000 min bias Pythia8 events; no Geant; no geometry) # o2-sim -j 1 -g pythia8pp -n ${NEVENTS} --noGeant --vertexMode kNoVertex &> sim.log +## Add --aod-writer-keep dangling to o2-sim-mctracks-to-aod to write the AO2D file to disc (as AnalysisResults_trees.root) # Option 1) -- use o2-mckine-publisher [ -f AnalysisResults.root ] && rm AnalysisResults.root o2-sim-kine-publisher -b --kineFileName o2sim --aggregate-timeframe 10 |\ @@ -19,8 +20,8 @@ mv AnalysisResults.root AnalysisResult_1.root # Option 2) -- use o2-sim-dpl-eventgen + extkinO2 generator (this should be equivalent to Option 1) [ -f AnalysisResults.root ] && rm AnalysisResults.root -o2-sim-dpl-eventgen -b --nevents ${NEVENTS} --aggregate-timeframe 10 --generator extkinO2 \ - --confKeyValues "GeneratorFromO2Kine.fileName=o2sim_Kine.root" --vertexMode kNoVertex |\ +o2-sim-dpl-eventgen -b --nEvents ${NEVENTS} --aggregate-timeframe 10 --generator extkinO2 \ + --configKeyValues "GeneratorFromO2Kine.fileName=o2sim_Kine.root" --vertexMode kNoVertex |\ o2-sim-mctracks-to-aod -b |\ o2-analysis-mctracks-to-aod-simple-task -b &> log2 mv AnalysisResults.root AnalysisResult_2.root diff --git a/run/SimExamples/McTracksToAOD/run_Pythia8.sh b/run/SimExamples/McTracksToAOD/run_Pythia8.sh index 8bac774c5892b..93d2024b05d37 100755 --- a/run/SimExamples/McTracksToAOD/run_Pythia8.sh +++ b/run/SimExamples/McTracksToAOD/run_Pythia8.sh @@ -8,7 +8,7 @@ NEVENTS=1000 # --aggregate-timeframe 10 is used to combine 10 generated events into a timeframe that is then converted to AOD tables # note that if you need special configuration for the analysis tasks, it needs to be passed to proxy and converter as well - +## Add --aod-writer-keep dangling to o2-sim-mctracks-to-aod to write the AO2D file to disc (as AnalysisResults_trees.root) o2-sim-dpl-eventgen -b --nEvents ${NEVENTS} --aggregate-timeframe 10 --generator pythia8pp --vertexMode kNoVertex |\ o2-sim-mctracks-to-aod -b | o2-analysis-mctracks-to-aod-simple-task -b &> pythia8.log diff --git a/run/SimExamples/McTracksToAOD/run_trigger.sh b/run/SimExamples/McTracksToAOD/run_trigger.sh index ca720191cbad2..5b278c0b666e5 100755 --- a/run/SimExamples/McTracksToAOD/run_trigger.sh +++ b/run/SimExamples/McTracksToAOD/run_trigger.sh @@ -5,9 +5,9 @@ set -x NEVENTS=1000 - +## Add --aod-writer-keep dangling to o2-sim-mctracks-to-aod to write the AO2D file to disc (as AnalysisResults_trees.root) CONFKEY="TriggerExternal.fileName=trigger.macro;TriggerExternal.funcName=trigger()" -o2-sim-dpl-eventgen -b --nevents ${NEVENTS} --aggregate-timeframe 10 --generator pythia8pp --trigger external \ - --vertexMode kDiamondParam --confKeyValues "${CONFKEY}" |\ +o2-sim-dpl-eventgen -b --nEvents ${NEVENTS} --aggregate-timeframe 10 --generator pythia8pp --trigger external \ + --vertexMode kDiamondParam --configKeyValues "${CONFKEY}" |\ o2-sim-mctracks-to-aod -b | o2-analysis-mctracks-to-aod-simple-task -b From 7c503090305ab42c607db29f49917e32dfd28023 Mon Sep 17 00:00:00 2001 From: Stefano Cannito <143754257+scannito@users.noreply.github.com> Date: Fri, 13 Feb 2026 17:44:23 +0100 Subject: [PATCH 200/234] [A3 TRK] Fix kCylinder option + services crossing (#15067) * Fix for kCylinder * Fix services crossing --- .../ALICE3/TRK/simulation/src/TRKLayer.cxx | 32 +++++++++---------- .../ALICE3/TRK/simulation/src/TRKServices.cxx | 4 +-- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx index 8d30cf9759e40..82b6fbd40af59 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx @@ -122,17 +122,12 @@ TGeoVolume* TRKLayer::createChip(std::string type) chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); sensVol = createSensor("cylinder"); - metalVol = createMetalStack("cylinder"); - - TGeoCombiTrans* transSens = new TGeoCombiTrans(); - transSens->SetTranslation(0, -(mChipThickness - mSensorThickness) / 2, 0); // TO BE CHECKED !!! LOGP(debug, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); - chipVol->AddNode(sensVol, 1, transSens); + chipVol->AddNode(sensVol, 1, nullptr); - TGeoCombiTrans* transMetal = new TGeoCombiTrans(); - transMetal->SetTranslation(0, mSensorThickness / 2, 0); // TO BE CHECKED !!! + metalVol = createMetalStack("cylinder"); LOGP(debug, "Inserting {} in {} ", metalVol->GetName(), chipVol->GetName()); - chipVol->AddNode(metalVol, 1, transMetal); + chipVol->AddNode(metalVol, 1, nullptr); // deadVol = createDeadzone("cylinder"); } else if (type == "flat") { @@ -175,7 +170,9 @@ TGeoVolume* TRKLayer::createModule(std::string type) TGeoVolume* moduleVol; if (type == "cylinder") { - module = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, (constants::moduleMLOT::length * mNumberOfModules) / 2); + double moduleLength = constants::moduleMLOT::length * mNumberOfModules; + + module = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, moduleLength / 2); moduleVol = new TGeoVolume(moduleName.c_str(), module, medSi); TGeoVolume* chipVol = createChip("cylinder"); @@ -229,8 +226,10 @@ TGeoVolume* TRKLayer::createHalfStave(std::string type) TGeoShape* halfStave; TGeoVolume* halfStaveVol; + double halfStaveLength = constants::moduleMLOT::length * mNumberOfModules; + if (type == "cylinder") { - halfStave = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, mChipLength / 2); + halfStave = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, halfStaveLength / 2); halfStaveVol = new TGeoVolume(halfStaveName.c_str(), halfStave, medSi); TGeoVolume* moduleVol = createModule("cylinder"); @@ -239,7 +238,6 @@ TGeoVolume* TRKLayer::createHalfStave(std::string type) } else if (type == "flat") { double moduleLength = constants::moduleMLOT::length; double halfStaveWidth = constants::OT::halfstave::width; - double halfStaveLength = constants::moduleMLOT::length * mNumberOfModules; halfStave = new TGeoBBox(halfStaveWidth / 2, mChipThickness / 2, halfStaveLength / 2); halfStaveVol = new TGeoVolume(halfStaveName.c_str(), halfStave, medSi); @@ -271,8 +269,10 @@ TGeoVolume* TRKLayer::createStave(std::string type) TGeoShape* stave; TGeoVolume* staveVol; + double staveLength = constants::moduleMLOT::length * mNumberOfModules; + if (type == "cylinder") { - stave = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, (constants::moduleMLOT::length * mNumberOfModules) / 2); + stave = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, staveLength / 2); staveVol = new TGeoVolume(staveName.c_str(), stave, medAir); TGeoVolume* moduleVol = createModule("cylinder"); @@ -281,7 +281,6 @@ TGeoVolume* TRKLayer::createStave(std::string type) } else if (type == "flat") { double moduleLength = constants::moduleMLOT::length; double staveWidth = constants::ML::width; - double staveLength = constants::moduleMLOT::length * mNumberOfModules; stave = new TGeoBBox(staveWidth / 2, mChipThickness / 2, staveLength / 2); staveVol = new TGeoVolume(staveName.c_str(), stave, medAir); @@ -304,7 +303,6 @@ TGeoVolume* TRKLayer::createStave(std::string type) double halfstaveWidth = constants::OT::halfstave::width; double staveWidth = constants::OT::width - overlap; - double staveLength = constants::moduleMLOT::length * mNumberOfModules; stave = new TGeoBBox(staveWidth / 2, mLogicalVolumeThickness / 2, staveLength / 2); staveVol = new TGeoVolume(staveName.c_str(), stave, medAir); @@ -343,15 +341,16 @@ void TRKLayer::createLayer(TGeoVolume* motherVolume) TGeoTube* layer; TGeoVolume* layerVol; + double layerLength = constants::moduleMLOT::length * mNumberOfModules; + if (mLayout == eLayout::kCylinder) { - layer = new TGeoTube(mInnerRadius - 0.333 * layerThickness, mInnerRadius + 0.667 * layerThickness, (constants::moduleMLOT::length * mNumberOfModules) / 2); + layer = new TGeoTube(mInnerRadius, mInnerRadius + mChipThickness, layerLength / 2); layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); TGeoVolume* staveVol = createStave("cylinder"); LOGP(debug, "Inserting {} in {} ", staveVol->GetName(), layerVol->GetName()); layerVol->AddNode(staveVol, 1, nullptr); } else if (mLayout == eLayout::kTurboStaves) { - double layerLength = constants::moduleMLOT::length * mNumberOfModules; double staveWidth = constants::ML::width; // Each stave has two modules (based on the LOI design) if (mInnerRadius > 25) { @@ -390,7 +389,6 @@ void TRKLayer::createLayer(TGeoVolume* motherVolume) } else if (mLayout == kStaggered) { double overlapInStave = constants::moduleMLOT::gaps::outerEdgeLongSide + constants::moduleMLOT::chip::passiveEdgeReadOut + 0.1; // 1.5mm outer-edge + 1mm deadzone + 1mm (true)overlap - double layerLength = constants::moduleMLOT::length * mNumberOfModules; double staveWidth = constants::OT::width - overlapInStave; layer = new TGeoTube(mInnerRadius - 0.333 * layerThickness, mInnerRadius + 0.667 * layerThickness, layerLength / 2); diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx index 51eea905c436a..cbe00e8fc9e89 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx @@ -264,7 +264,7 @@ void TRKServices::createMiddleServices(TGeoVolume* motherVolume) // Carbon Fiber Cylinder support for the middle tracker float rMinMiddleCarbonSupport = 34.8f; // Arbitrary value float rMaxMiddleCarbonSupport = 35.f; // 2 mm of carbon fiber - const float zLengthMiddleCarbon = 62.f; + const float zLengthMiddleCarbon = 64.2f; TGeoTube* middleBarrelCarbonSupport = new TGeoTube("TRK_MID_CARBONSUPPORTsh", rMinMiddleCarbonSupport, rMaxMiddleCarbonSupport, zLengthMiddleCarbon); TGeoVolume* middleBarrelCarbonSupportVolume = new TGeoVolume("TRK_MID_CARBONSUPPORT", middleBarrelCarbonSupport, medCFiber); middleBarrelCarbonSupportVolume->SetLineColor(kGray); @@ -318,7 +318,7 @@ void TRKServices::createMiddleServices(TGeoVolume* motherVolume) // Middle barrel connection disks const float rMinMiddleBarrelDisk = 5.68f; const float rMaxMiddleBarrelDisk = 35.f; - const float zLengthMiddleBarrel = 62.f; + const float zLengthMiddleBarrel = 64.2f; for (auto& orientation : {Orientation::kASide, Orientation::kCSide}) { TGeoTube* middleBarrelConnDiskSIO2 = new TGeoTube(Form("TRK_MIDBARCONN_DISK_SIO2sh_%s", orientation == Orientation::kASide ? "bwd" : "fwd"), rMinMiddleBarrelDisk, rMaxMiddleBarrelDisk, siO2FiberThick); TGeoTube* middleBarrelConnDiskPE = new TGeoTube(Form("TRK_MIDBARCONN_DISK_PEsh_%s", orientation == Orientation::kASide ? "bwd" : "fwd"), rMinMiddleBarrelDisk, rMaxMiddleBarrelDisk, peFiberThick); From 48c0b5433f9d4f7af17e8ad34ea6e3363fce5963 Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Sun, 8 Feb 2026 19:17:34 +0100 Subject: [PATCH 201/234] Support to plug-and-play external (CAD) geometry This commit adds support for - conversion from CAD geometries (STEP) file to (meshed) TGeo geometry via the tool O2_CADtoTGeo.py - ability to setup and include simulations modules from external geometries via the ExternalModule mechanism - ability to navigate complex TGeoTessellated solids efficiently (will stay here until fully integrated in the official ROOT repo) It includes all the (basic) functionality to pick a detector layout from a CAD design and actually simulate it with o2-sim. Instructions are provided in a dedicated documentation markdown. The commit is related to epic https://its.cern.ch/jira/browse/O2-6616 --- Detectors/Base/CMakeLists.txt | 7 +- .../include/DetectorsBase/O2Tessellated.h | 142 ++ .../include/DetectorsBase/TGeoGeometryUtils.h | 38 + Detectors/Base/src/DetectorsBaseLinkDef.h | 2 + Detectors/Base/src/O2Tessellated.cxx | 1509 +++++++++++++++++ Detectors/Base/src/TGeoGeometryUtils.cxx | 144 ++ Detectors/Base/src/bvh2_extra_kernels.h | 79 + Detectors/Base/src/bvh2_third_party.h | 49 + Detectors/Passive/CMakeLists.txt | 2 + .../include/DetectorsPassive/ExternalModule.h | 64 + Detectors/Passive/src/ExternalModule.cxx | 175 ++ Steer/include/Steer/O2MCApplicationBase.h | 2 + Steer/src/O2MCApplication.cxx | 60 + macro/build_geometry.C | 14 + scripts/geometry/O2_CADtoTGeo.py | 602 +++++++ scripts/geometry/README.md | 27 + scripts/geometry/simulating_CAD_modules.md | 72 + 17 files changed, 2987 insertions(+), 1 deletion(-) create mode 100644 Detectors/Base/include/DetectorsBase/O2Tessellated.h create mode 100644 Detectors/Base/include/DetectorsBase/TGeoGeometryUtils.h create mode 100644 Detectors/Base/src/O2Tessellated.cxx create mode 100644 Detectors/Base/src/TGeoGeometryUtils.cxx create mode 100644 Detectors/Base/src/bvh2_extra_kernels.h create mode 100644 Detectors/Base/src/bvh2_third_party.h create mode 100644 Detectors/Passive/include/DetectorsPassive/ExternalModule.h create mode 100644 Detectors/Passive/src/ExternalModule.cxx create mode 100644 scripts/geometry/O2_CADtoTGeo.py create mode 100644 scripts/geometry/README.md create mode 100644 scripts/geometry/simulating_CAD_modules.md diff --git a/Detectors/Base/CMakeLists.txt b/Detectors/Base/CMakeLists.txt index 30ab4c4fe8a40..83a9193274e4f 100644 --- a/Detectors/Base/CMakeLists.txt +++ b/Detectors/Base/CMakeLists.txt @@ -29,6 +29,8 @@ o2_add_library(DetectorsBase src/Stack.cxx src/VMCSeederService.cxx src/GlobalParams.cxx + src/O2Tessellated.cxx + src/TGeoGeometryUtils.cxx PUBLIC_LINK_LIBRARIES FairRoot::Base O2::CommonUtils O2::DetectorsCommonDataFormats @@ -46,6 +48,7 @@ o2_add_library(DetectorsBase O2::GPUDataTypes MC::VMC TBB::tbb + ROOT::Gdml ) o2_target_root_dictionary(DetectorsBase @@ -62,7 +65,9 @@ o2_target_root_dictionary(DetectorsBase include/DetectorsBase/Aligner.h include/DetectorsBase/Stack.h include/DetectorsBase/SimFieldUtils.h - include/DetectorsBase/GlobalParams.h) + include/DetectorsBase/GlobalParams.h + include/DetectorsBase/O2Tessellated.h + ) if(BUILD_SIMULATION) if (NOT APPLE) diff --git a/Detectors/Base/include/DetectorsBase/O2Tessellated.h b/Detectors/Base/include/DetectorsBase/O2Tessellated.h new file mode 100644 index 0000000000000..0a1cee8b3e01f --- /dev/null +++ b/Detectors/Base/include/DetectorsBase/O2Tessellated.h @@ -0,0 +1,142 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_BASE_O2TESSELLATED_ +#define ALICEO2_BASE_O2TESSELLATED_ + +#include "TGeoShape.h" +#include "TGeoBBox.h" +#include "TGeoVector3.h" +#include "TGeoTypedefs.h" +#include "TGeoTessellated.h" + +namespace o2 +{ +namespace base +{ + +class O2Tessellated : public TGeoBBox +{ + + public: + using Vertex_t = Tessellated::Vertex_t; + + private: + int fNfacets = 0; // Number of facets + int fNvert = 0; // Number of vertices + int fNseg = 0; // Number of segments + bool fDefined = false; //! Shape fully defined + bool fClosedBody = false; // The faces are making a closed body + + // for now separate vectors but might be better to group per face + std::vector fVertices; // List of vertices + std::vector fFacets; // List of facets + std::vector fOutwardNormals; // Vector of outward-facing normals (to be streamed !) + + std::multimap fVerticesMap; //! Temporary map used to deduplicate vertices + bool fIsClosed = false; //! to know if shape still needs closure/initialization + void* fBVH = nullptr; //! BVH acceleration structure for safety and navigation + + O2Tessellated(const O2Tessellated&) = delete; + O2Tessellated& operator=(const O2Tessellated&) = delete; + + // bvh helper functions + void BuildBVH(); + void CalculateNormals(); + + public: + // constructors + O2Tessellated() {} + O2Tessellated(const char* name, int nfacets = 0); + O2Tessellated(const char* name, const std::vector& vertices); + // from a TGeoTessellated + O2Tessellated(TGeoTessellated const&, bool check = false); + + // destructor + ~O2Tessellated() override {} + + void ComputeBBox() override; + void CloseShape(bool check = true, bool fixFlipped = true, bool verbose = true); + + bool AddFacet(const Vertex_t& pt0, const Vertex_t& pt1, const Vertex_t& pt2); + bool AddFacet(const Vertex_t& pt0, const Vertex_t& pt1, const Vertex_t& pt2, const Vertex_t& pt3); + bool AddFacet(int i1, int i2, int i3); + bool AddFacet(int i1, int i2, int i3, int i4); + int AddVertex(const Vertex_t& vert); + + bool FacetCheck(int ifacet) const; + Vertex_t FacetComputeNormal(int ifacet, bool& degenerated) const; + + int GetNfacets() const { return fFacets.size(); } + int GetNsegments() const { return fNseg; } + int GetNvertices() const { return fNvert; } + bool IsClosedBody() const { return fClosedBody; } + bool IsDefined() const { return fDefined; } + + const TGeoFacet& GetFacet(int i) const { return fFacets[i]; } + const Vertex_t& GetVertex(int i) const { return fVertices[i]; } + + int DistancetoPrimitive(int, int) override { return 99999; } + const TBuffer3D& GetBuffer3D(int reqSections, Bool_t localFrame) const override; + void GetMeshNumbers(int& nvert, int& nsegs, int& npols) const override; + int GetNmeshVertices() const override { return fNvert; } + void InspectShape() const override {} + TBuffer3D* MakeBuffer3D() const override; + void Print(Option_t* option = "") const override; + void SavePrimitive(std::ostream&, Option_t*) override {} + void SetPoints(double* points) const override; + void SetPoints(Float_t* points) const override; + void SetSegsAndPols(TBuffer3D& buff) const override; + void Sizeof3D() const override {} + + /// Resize and center the shape in a box of size maxsize + void ResizeCenter(double maxsize); + + /// Flip all facets + void FlipFacets() + { + for (auto facet : fFacets) + facet.Flip(); + } + + bool CheckClosure(bool fixFlipped = true, bool verbose = true); + + /// Reader from .obj format + static O2Tessellated* ImportFromObjFormat(const char* objfile, bool check = false, bool verbose = false); + + // navigation functions used by TGeoNavigator (attention: only the iact == 3 cases implemented for now) + Double_t DistFromOutside(const Double_t* point, const Double_t* dir, Int_t iact = 1, + Double_t step = TGeoShape::Big(), Double_t* safe = nullptr) const override; + Double_t DistFromInside(const Double_t* point, const Double_t* dir, Int_t iact = 1, Double_t step = TGeoShape::Big(), + Double_t* safe = nullptr) const override; + bool Contains(const Double_t* point) const override; + Double_t Safety(const Double_t* point, Bool_t in = kTRUE) const override; + void ComputeNormal(const Double_t* point, const Double_t* dir, Double_t* norm) const override; + + // these are trivial implementations, just for debugging + Double_t DistFromInside_Loop(const Double_t* point, const Double_t* dir) const; + Double_t DistFromOutside_Loop(const Double_t* point, const Double_t* dir) const; + bool Contains_Loop(const Double_t* point) const; + + Double_t Capacity() const override; + + private: + // a safety kernel used in multiple implementations + template + Double_t SafetyKernel(const Double_t* point, bool in, int* closest_facet_id = nullptr) const; + + ClassDefOverride(O2Tessellated, 1) // tessellated shape class +}; + +} // namespace base +} // namespace o2 + +#endif diff --git a/Detectors/Base/include/DetectorsBase/TGeoGeometryUtils.h b/Detectors/Base/include/DetectorsBase/TGeoGeometryUtils.h new file mode 100644 index 0000000000000..5ec85f1c14702 --- /dev/null +++ b/Detectors/Base/include/DetectorsBase/TGeoGeometryUtils.h @@ -0,0 +1,38 @@ +// 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 TGeoGeometryUtils.h +/// \author Sandro Wenzel (CERN) +/// \brief Collection of utility functions for TGeo + +#ifndef ALICEO2_BASE_TGEOGEOMETRYUTILS_H_ +#define ALICEO2_BASE_TGEOGEOMETRYUTILS_H_ + +class TGeoShape; +class TGeoTessellated; + +namespace o2 +{ +namespace base +{ + +/// A few utility functions to operate on TGeo geometries (transformations, printing, ...) +class TGeoGeometryUtils +{ + public: + ///< Transform any (primitive) TGeoShape to a tessellated representation + static TGeoTessellated* TGeoShapeToTGeoTessellated(TGeoShape const*); +}; + +} // namespace base +} // namespace o2 + +#endif diff --git a/Detectors/Base/src/DetectorsBaseLinkDef.h b/Detectors/Base/src/DetectorsBaseLinkDef.h index bd76e9bfbe2e4..8255c143ebb4a 100644 --- a/Detectors/Base/src/DetectorsBaseLinkDef.h +++ b/Detectors/Base/src/DetectorsBaseLinkDef.h @@ -42,4 +42,6 @@ #pragma link C++ class o2::data::Stack + ; +#pragma link C++ class o2::base::O2Tessellated - ; + #endif diff --git a/Detectors/Base/src/O2Tessellated.cxx b/Detectors/Base/src/O2Tessellated.cxx new file mode 100644 index 0000000000000..256a70e5a697a --- /dev/null +++ b/Detectors/Base/src/O2Tessellated.cxx @@ -0,0 +1,1509 @@ +// 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. + +// Sandro Wenzel 2026 + +// An implementation of TGeoTessellated augmented with efficient navigation functions. +// Asked for integration into ROOT here https://github.com/root-project/root/pull/21045 +// Will be deleted once we get this from ROOT. + +#include +#include + +#include "TGeoManager.h" +#include "TGeoMatrix.h" +#include "TGeoVolume.h" +#include "TVirtualGeoPainter.h" +#include "DetectorsBase/O2Tessellated.h" +#include "TBuffer3D.h" +#include "TBuffer3DTypes.h" +#include "TMath.h" +#include "TBuffer.h" + +#include +#include + +// THIS IS THIRD PARTY CODE (TO BE PUT IN ROOT) WHICH DOES NOT NEED TO ADHERE TO OUR LINTING +// NOLINTBEGIN + +// include the Third-party BVH headers +#include "bvh2_third_party.h" +// some kernels on top of BVH +#include "bvh2_extra_kernels.h" + +#include +#include + +using namespace o2::base; +ClassImp(O2Tessellated); + +using Vertex_t = Tessellated::Vertex_t; + +//////////////////////////////////////////////////////////////////////////////// +/// Compact consecutive equal vertices + +int TGeoFacet::CompactFacet(Vertex_t* vert, int nvertices) +{ + // Compact the common vertices and return new facet + if (nvertices < 2) + return nvertices; + int nvert = nvertices; + int i = 0; + while (i < nvert) { + if (vert[(i + 1) % nvert] == vert[i]) { + // shift last vertices left by one element + for (int j = i + 2; j < nvert; ++j) + vert[j - 1] = vert[j]; + nvert--; + } + i++; + } + return nvert; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Check if a connected neighbour facet has compatible normal + +bool TGeoFacet::IsNeighbour(const TGeoFacet& other, bool& flip) const +{ + + // Find a connecting segment + bool neighbour = false; + int line1[2], line2[2]; + int npoints = 0; + for (int i = 0; i < fNvert; ++i) { + auto ivert = fIvert[i]; + // Check if the other facet has the same vertex + for (int j = 0; j < other.GetNvert(); ++j) { + if (ivert == other[j]) { + line1[npoints] = i; + line2[npoints] = j; + if (++npoints == 2) { + neighbour = true; + bool order1 = line1[1] == line1[0] + 1; + bool order2 = line2[1] == (line2[0] + 1) % other.GetNvert(); + flip = (order1 == order2); + return neighbour; + } + } + } + } + return neighbour; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Constructor. In case nfacets is zero, it is user's responsibility to +/// call CloseShape once all faces are defined. + +O2Tessellated::O2Tessellated(const char* name, int nfacets) : TGeoBBox(name, 0, 0, 0) +{ + fNfacets = nfacets; + if (nfacets) + fFacets.reserve(nfacets); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Constructor providing directly the array of vertices. Facets have to be added +/// providing vertex indices rather than coordinates. + +O2Tessellated::O2Tessellated(const char* name, const std::vector& vertices) : TGeoBBox(name, 0, 0, 0) +{ + fVertices = vertices; + fNvert = fVertices.size(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Construct from TGeoTessellated + +O2Tessellated::O2Tessellated(TGeoTessellated const& tsl, bool check) : TGeoBBox(tsl.GetName(), 0, 0, 0) +{ + fNfacets = tsl.GetNfacets(); + fNvert = tsl.GetNvertices(); + fNseg = tsl.GetNsegments(); + + // copy facet and vertex done + fVertices.reserve(fNvert); + fFacets.reserve(fNfacets); + for (int i = 0; i < fNfacets; ++i) { + fFacets.push_back(tsl.GetFacet(i)); + } + for (int i = 0; i < fNvert; ++i) { + fVertices.push_back(tsl.GetVertex(i)); + } + // finish remaining structures + CloseShape(check); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Add a vertex checking for duplicates, returning the vertex index + +int O2Tessellated::AddVertex(Vertex_t const& vert) +{ + constexpr double tolerance = 1.e-10; + auto vertexHash = [&](Vertex_t const& vertex) { + // Compute hash for the vertex + long hash = 0; + // helper function to generate hash from integer numbers + auto hash_combine = [](long seed, const long value) { + return seed ^ (std::hash{}(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2)); + }; + for (int i = 0; i < 3; i++) { + // use tolerance to generate int with the desired precision from a real number for hashing + hash = hash_combine(hash, std::roundl(vertex[i] / tolerance)); + } + return hash; + }; + + auto hash = vertexHash(vert); + bool isAdded = false; + int ivert = -1; + // Get the compatible vertices + auto range = fVerticesMap.equal_range(hash); + for (auto it = range.first; it != range.second; ++it) { + ivert = it->second; + if (fVertices[ivert] == vert) { + isAdded = true; + break; + } + } + if (!isAdded) { + ivert = fVertices.size(); + fVertices.push_back(vert); + fVerticesMap.insert(std::make_pair(hash, ivert)); + } + return ivert; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Adding a triangular facet from vertex positions in absolute coordinates + +bool O2Tessellated::AddFacet(const Vertex_t& pt0, const Vertex_t& pt1, const Vertex_t& pt2) +{ + if (fDefined) { + Error("AddFacet", "Shape %s already fully defined. Not adding", GetName()); + return false; + } + + Vertex_t vert[3]; + vert[0] = pt0; + vert[1] = pt1; + vert[2] = pt2; + int nvert = TGeoFacet::CompactFacet(vert, 3); + if (nvert < 3) { + Error("AddFacet", "Triangular facet at index %d degenerated. Not adding.", GetNfacets()); + return false; + } + int ind[3]; + for (auto i = 0; i < 3; ++i) + ind[i] = AddVertex(vert[i]); + fNseg += 3; + fFacets.emplace_back(ind[0], ind[1], ind[2]); + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Adding a triangular facet from indices of vertices + +bool O2Tessellated::AddFacet(int i0, int i1, int i2) +{ + if (fDefined) { + Error("AddFacet", "Shape %s already fully defined. Not adding", GetName()); + return false; + } + if (fVertices.empty()) { + Error("AddFacet", "Shape %s Cannot add facets by indices without vertices. Not adding", GetName()); + return false; + } + + fNseg += 3; + fFacets.emplace_back(i0, i1, i2); + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Adding a quadrilateral facet from vertex positions in absolute coordinates + +bool O2Tessellated::AddFacet(const Vertex_t& pt0, const Vertex_t& pt1, const Vertex_t& pt2, const Vertex_t& pt3) +{ + if (fDefined) { + Error("AddFacet", "Shape %s already fully defined. Not adding", GetName()); + return false; + } + Vertex_t vert[4]; + vert[0] = pt0; + vert[1] = pt1; + vert[2] = pt2; + vert[3] = pt3; + int nvert = TGeoFacet::CompactFacet(vert, 4); + if (nvert < 3) { + Error("AddFacet", "Quadrilateral facet at index %d degenerated. Not adding.", GetNfacets()); + return false; + } + + int ind[4]; + for (auto i = 0; i < nvert; ++i) + ind[i] = AddVertex(vert[i]); + fNseg += nvert; + if (nvert == 3) + fFacets.emplace_back(ind[0], ind[1], ind[2]); + else + fFacets.emplace_back(ind[0], ind[1], ind[2], ind[3]); + + if (fNfacets > 0 && GetNfacets() == fNfacets) + CloseShape(false); + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Adding a quadrilateral facet from indices of vertices + +bool O2Tessellated::AddFacet(int i0, int i1, int i2, int i3) +{ + if (fDefined) { + Error("AddFacet", "Shape %s already fully defined. Not adding", GetName()); + return false; + } + if (fVertices.empty()) { + Error("AddFacet", "Shape %s Cannot add facets by indices without vertices. Not adding", GetName()); + return false; + } + + fNseg += 4; + fFacets.emplace_back(i0, i1, i2, i3); + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Compute normal for a given facet + +Vertex_t O2Tessellated::FacetComputeNormal(int ifacet, bool& degenerated) const +{ + // Compute normal using non-zero segments + constexpr double kTolerance = 1.e-20; + auto const& facet = fFacets[ifacet]; + int nvert = facet.GetNvert(); + degenerated = true; + Vertex_t normal; + for (int i = 0; i < nvert - 1; ++i) { + Vertex_t e1 = fVertices[facet[i + 1]] - fVertices[facet[i]]; + if (e1.Mag2() < kTolerance) + continue; + for (int j = i + 1; j < nvert; ++j) { + Vertex_t e2 = fVertices[facet[(j + 1) % nvert]] - fVertices[facet[j]]; + if (e2.Mag2() < kTolerance) + continue; + normal = Vertex_t::Cross(e1, e2); + // e1 and e2 may be colinear + if (normal.Mag2() < kTolerance) + continue; + normal.Normalize(); + degenerated = false; + break; + } + if (!degenerated) + break; + } + return normal; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Check validity of facet + +bool O2Tessellated::FacetCheck(int ifacet) const +{ + constexpr double kTolerance = 1.e-10; + auto const& facet = fFacets[ifacet]; + int nvert = facet.GetNvert(); + bool degenerated = true; + FacetComputeNormal(ifacet, degenerated); + if (degenerated) { + std::cout << "Facet: " << ifacet << " is degenerated\n"; + return false; + } + + // Compute surface area + double surfaceArea = 0.; + for (int i = 1; i < nvert - 1; ++i) { + Vertex_t e1 = fVertices[facet[i]] - fVertices[facet[0]]; + Vertex_t e2 = fVertices[facet[i + 1]] - fVertices[facet[0]]; + surfaceArea += 0.5 * Vertex_t::Cross(e1, e2).Mag(); + } + if (surfaceArea < kTolerance) { + std::cout << "Facet: " << ifacet << " has zero surface area\n"; + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Close the shape: calculate bounding box and compact vertices + +void O2Tessellated::CloseShape(bool check, bool fixFlipped, bool verbose) +{ + if (fIsClosed && fBVH) { + return; + } + // Compute bounding box + fDefined = true; + fNvert = fVertices.size(); + fNfacets = fFacets.size(); + ComputeBBox(); + + BuildBVH(); + if (fOutwardNormals.size() == 0) { + CalculateNormals(); + } else { + // short check if the normal container is of correct size + if (fOutwardNormals.size() != fFacets.size()) { + std::cerr << "Inconsistency in normal container"; + } + } + fIsClosed = true; + + // Cleanup the vertex map + std::multimap().swap(fVerticesMap); + + if (fVertices.size() > 0) { + if (!check) + return; + + // Check facets + for (auto i = 0; i < fNfacets; ++i) + FacetCheck(i); + + fClosedBody = CheckClosure(fixFlipped, verbose); + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Check closure of the solid and check/fix flipped normals + +bool O2Tessellated::CheckClosure(bool fixFlipped, bool verbose) +{ + int* nn = new int[fNfacets]; + bool* flipped = new bool[fNfacets]; + bool hasorphans = false; + bool hasflipped = false; + for (int i = 0; i < fNfacets; ++i) { + nn[i] = 0; + flipped[i] = false; + } + + for (int icrt = 0; icrt < fNfacets; ++icrt) { + // all neighbours checked? + if (nn[icrt] >= fFacets[icrt].GetNvert()) + continue; + for (int i = icrt + 1; i < fNfacets; ++i) { + bool isneighbour = fFacets[icrt].IsNeighbour(fFacets[i], flipped[i]); + if (isneighbour) { + if (flipped[icrt]) + flipped[i] = !flipped[i]; + if (flipped[i]) + hasflipped = true; + nn[icrt]++; + nn[i]++; + if (nn[icrt] == fFacets[icrt].GetNvert()) + break; + } + } + if (nn[icrt] < fFacets[icrt].GetNvert()) + hasorphans = true; + } + + if (hasorphans && verbose) { + Error("Check", "Tessellated solid %s has following not fully connected facets:", GetName()); + for (int icrt = 0; icrt < fNfacets; ++icrt) { + if (nn[icrt] < fFacets[icrt].GetNvert()) + std::cout << icrt << " (" << fFacets[icrt].GetNvert() << " edges, " << nn[icrt] << " neighbours)\n"; + } + } + fClosedBody = !hasorphans; + int nfixed = 0; + if (hasflipped) { + if (verbose) + Warning("Check", "Tessellated solid %s has following facets with flipped normals:", GetName()); + for (int icrt = 0; icrt < fNfacets; ++icrt) { + if (flipped[icrt]) { + if (verbose) + std::cout << icrt << "\n"; + if (fixFlipped) { + fFacets[icrt].Flip(); + nfixed++; + } + } + } + if (nfixed && verbose) + Info("Check", "Automatically flipped %d facets to match first defined facet", nfixed); + } + delete[] nn; + delete[] flipped; + + return !hasorphans; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Compute bounding box + +void O2Tessellated::ComputeBBox() +{ + const double kBig = TGeoShape::Big(); + double vmin[3] = {kBig, kBig, kBig}; + double vmax[3] = {-kBig, -kBig, -kBig}; + for (const auto& facet : fFacets) { + for (int i = 0; i < facet.GetNvert(); ++i) { + for (int j = 0; j < 3; ++j) { + vmin[j] = TMath::Min(vmin[j], fVertices[facet[i]].operator[](j)); + vmax[j] = TMath::Max(vmax[j], fVertices[facet[i]].operator[](j)); + } + } + } + fDX = 0.5 * (vmax[0] - vmin[0]); + fDY = 0.5 * (vmax[1] - vmin[1]); + fDZ = 0.5 * (vmax[2] - vmin[2]); + for (int i = 0; i < 3; ++i) + fOrigin[i] = 0.5 * (vmax[i] + vmin[i]); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Returns numbers of vertices, segments and polygons composing the shape mesh. + +void O2Tessellated::GetMeshNumbers(int& nvert, int& nsegs, int& npols) const +{ + nvert = fNvert; + nsegs = fNseg; + npols = GetNfacets(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Creates a TBuffer3D describing *this* shape. +/// Coordinates are in local reference frame. + +TBuffer3D* O2Tessellated::MakeBuffer3D() const +{ + const int nvert = fNvert; + const int nsegs = fNseg; + const int npols = GetNfacets(); + auto buff = new TBuffer3D(TBuffer3DTypes::kGeneric, nvert, 3 * nvert, nsegs, 3 * nsegs, npols, 6 * npols); + if (buff) { + SetPoints(buff->fPnts); + SetSegsAndPols(*buff); + } + return buff; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Prints basic info + +void O2Tessellated::Print(Option_t*) const +{ + std::cout << "=== Tessellated shape " << GetName() << " having " << GetNvertices() << " vertices and " + << GetNfacets() << " facets\n"; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Fills TBuffer3D structure for segments and polygons. + +void O2Tessellated::SetSegsAndPols(TBuffer3D& buff) const +{ + const int c = GetBasicColor(); + int* segs = buff.fSegs; + int* pols = buff.fPols; + + int indseg = 0; // segment internal data index + int indpol = 0; // polygon internal data index + int sind = 0; // segment index + for (const auto& facet : fFacets) { + auto nvert = facet.GetNvert(); + pols[indpol++] = c; + pols[indpol++] = nvert; + for (auto j = 0; j < nvert; ++j) { + int k = (j + 1) % nvert; + // segment made by next consecutive points + segs[indseg++] = c; + segs[indseg++] = facet[j]; + segs[indseg++] = facet[k]; + // add segment to current polygon and increment segment index + pols[indpol + nvert - j - 1] = sind++; + } + indpol += nvert; + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Fill tessellated points to an array. + +void O2Tessellated::SetPoints(double* points) const +{ + int ind = 0; + for (const auto& vertex : fVertices) { + vertex.CopyTo(&points[ind]); + ind += 3; + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Fill tessellated points in float. + +void O2Tessellated::SetPoints(Float_t* points) const +{ + int ind = 0; + for (const auto& vertex : fVertices) { + points[ind++] = vertex.x(); + points[ind++] = vertex.y(); + points[ind++] = vertex.z(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Resize the shape by scaling vertices within maxsize and center to origin + +void O2Tessellated::ResizeCenter(double maxsize) +{ + using Vector3_t = Vertex_t; + + if (!fDefined) { + Error("ResizeCenter", "Not all faces are defined"); + return; + } + Vector3_t origin(fOrigin[0], fOrigin[1], fOrigin[2]); + double maxedge = TMath::Max(TMath::Max(fDX, fDY), fDZ); + double scale = maxsize / maxedge; + for (size_t i = 0; i < fVertices.size(); ++i) { + fVertices[i] = scale * (fVertices[i] - origin); + } + fOrigin[0] = fOrigin[1] = fOrigin[2] = 0; + fDX *= scale; + fDY *= scale; + fDZ *= scale; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Fills a static 3D buffer and returns a reference. + +const TBuffer3D& O2Tessellated::GetBuffer3D(int reqSections, Bool_t localFrame) const +{ + static TBuffer3D buffer(TBuffer3DTypes::kGeneric); + + FillBuffer3D(buffer, reqSections, localFrame); + + const int nvert = fNvert; + const int nsegs = fNseg; + const int npols = GetNfacets(); + + if (reqSections & TBuffer3D::kRawSizes) { + if (buffer.SetRawSizes(nvert, 3 * nvert, nsegs, 3 * nsegs, npols, 6 * npols)) { + buffer.SetSectionsValid(TBuffer3D::kRawSizes); + } + } + if ((reqSections & TBuffer3D::kRaw) && buffer.SectionsValid(TBuffer3D::kRawSizes)) { + SetPoints(buffer.fPnts); + if (!buffer.fLocalFrame) { + TransformPoints(buffer.fPnts, buffer.NbPnts()); + } + + SetSegsAndPols(buffer); + buffer.SetSectionsValid(TBuffer3D::kRaw); + } + + return buffer; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Reads a single tessellated solid from an .obj file. + +O2Tessellated* O2Tessellated::ImportFromObjFormat(const char* objfile, bool check, bool verbose) +{ + using std::vector, std::string, std::ifstream, std::stringstream, std::endl; + + vector vertices; + vector sfacets; + + struct FacetInd_t { + int i0 = -1; + int i1 = -1; + int i2 = -1; + int i3 = -1; + int nvert = 0; + FacetInd_t(int a, int b, int c) + { + i0 = a; + i1 = b; + i2 = c; + nvert = 3; + }; + FacetInd_t(int a, int b, int c, int d) + { + i0 = a; + i1 = b; + i2 = c; + i3 = d; + nvert = 4; + }; + }; + + vector facets; + // List of geometric vertices, with (x, y, z [,w]) coordinates, w is optional and defaults to 1.0. + // struct vtx_t { double x = 0; double y = 0; double z = 0; double w = 1; }; + + // Texture coordinates in u, [,v ,w]) coordinates, these will vary between 0 and 1. v, w are optional and default to + // 0. + // struct tex_t { double u; double v; double w; }; + + // List of vertex normals in (x,y,z) form; normals might not be unit vectors. + // struct vn_t { double x; double y; double z; }; + + // Parameter space vertices in ( u [,v] [,w] ) form; free form geometry statement + // struct vp_t { double u; double v; double w; }; + + // Faces are defined using lists of vertex, texture and normal indices which start at 1. + // Polygons such as quadrilaterals can be defined by using more than three vertex/texture/normal indices. + // f v1//vn1 v2//vn2 v3//vn3 ... + + // Records starting with the letter "l" specify the order of the vertices which build a polyline. + // l v1 v2 v3 v4 v5 v6 ... + + string line; + int ind[4] = {0}; + ifstream file(objfile); + if (!file.is_open()) { + ::Error("O2Tessellated::ImportFromObjFormat", "Unable to open %s", objfile); + return nullptr; + } + + while (getline(file, line)) { + stringstream ss(line); + string tag; + + // We ignore everything which is not a vertex or a face + if (line.rfind('v', 0) == 0 && line.rfind("vt", 0) != 0 && line.rfind("vn", 0) != 0 && line.rfind("vn", 0) != 0) { + // Decode the vertex + double pos[4] = {0, 0, 0, 1}; + ss >> tag >> pos[0] >> pos[1] >> pos[2] >> pos[3]; + vertices.emplace_back(pos[0] * pos[3], pos[1] * pos[3], pos[2] * pos[3]); + } + + else if (line.rfind('f', 0) == 0) { + // Decode the face + ss >> tag; + string word; + sfacets.clear(); + while (ss >> word) + sfacets.push_back(word); + if (sfacets.size() > 4 || sfacets.size() < 3) { + ::Error("O2Tessellated::ImportFromObjFormat", "Detected face having unsupported %zu vertices", + sfacets.size()); + return nullptr; + } + int nvert = 0; + for (auto& sword : sfacets) { + stringstream ssword(sword); + string token; + getline(ssword, token, '/'); // just need the vertex index, which is the first token + // Convert string token to integer + + ind[nvert++] = stoi(token) - 1; + if (ind[nvert - 1] < 0) { + ::Error("O2Tessellated::ImportFromObjFormat", "Unsupported relative vertex index definition in %s", + objfile); + return nullptr; + } + } + if (nvert == 3) + facets.emplace_back(ind[0], ind[1], ind[2]); + else + facets.emplace_back(ind[0], ind[1], ind[2], ind[3]); + } + } + + int nvertices = (int)vertices.size(); + int nfacets = (int)facets.size(); + if (nfacets < 3) { + ::Error("O2Tessellated::ImportFromObjFormat", "Not enough faces detected in %s", objfile); + return nullptr; + } + + string sobjfile(objfile); + if (verbose) + std::cout << "Read " << nvertices << " vertices and " << nfacets << " facets from " << sobjfile << endl; + + auto tsl = new O2Tessellated(sobjfile.erase(sobjfile.find_last_of('.')).c_str(), vertices); + + for (int i = 0; i < nfacets; ++i) { + auto facet = facets[i]; + if (facet.nvert == 3) + tsl->AddFacet(facet.i0, facet.i1, facet.i2); + else + tsl->AddFacet(facet.i0, facet.i1, facet.i2, facet.i3); + } + tsl->CloseShape(check, true, verbose); + tsl->Print(); + return tsl; +} + +// implementation of some geometry helper functions in anonymous namespace +namespace +{ + +using Vertex_t = Tessellated::Vertex_t; +// The classic Moeller-Trumbore ray triangle-intersection kernel: +// - Compute triangle edges e1, e2 +// - Compute determinant det +// - Reject parallel rays +// - Compute barycentric coordinates u, v +// - Compute ray parameter t +double rayTriangle(const Vertex_t& orig, const Vertex_t& dir, const Vertex_t& v0, const Vertex_t& v1, + const Vertex_t& v2, double rayEPS = 1e-8) +{ + constexpr double EPS = 1e-8; + const double INF = std::numeric_limits::infinity(); + Vertex_t e1{v1[0] - v0[0], v1[1] - v0[1], v1[2] - v0[2]}; + Vertex_t e2{v2[0] - v0[0], v2[1] - v0[1], v2[2] - v0[2]}; + auto p = Vertex_t::Cross(dir, e2); + auto det = e1.Dot(p); + if (std::abs(det) <= EPS) { + return INF; + } + + Vertex_t tvec{orig[0] - v0[0], orig[1] - v0[1], orig[2] - v0[2]}; + auto invDet = 1.0 / det; + auto u = tvec.Dot(p) * invDet; + if (u < 0.0 || u > 1.0) { + return INF; + } + auto q = Vertex_t::Cross(tvec, e1); + auto v = dir.Dot(q) * invDet; + if (v < 0.0 || u + v > 1.0) { + return INF; + } + auto t = e2.Dot(q) * invDet; + return (t > rayEPS) ? t : INF; +} + +template +struct Vec3f { + T x, y, z; +}; + +template +inline Vec3f operator-(const Vec3f& a, const Vec3f& b) +{ + return {a.x - b.x, a.y - b.y, a.z - b.z}; +} + +template +inline Vec3f cross(const Vec3f& a, const Vec3f& b) +{ + return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x}; +} + +template +inline T dot(const Vec3f& a, const Vec3f& b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z; +} + +// Kernel to get closest/shortest distance between a point and a triangl (a,b,c). +// Performed by default in float since Safety can be approximate. +// Project point onto triangle plane +// If projection lies inside → distance to plane +// Otherwise compute min distance to the three edges +// Return squared distance +template +T pointTriangleDistSq(const Vec3f& p, const Vec3f& a, const Vec3f& b, const Vec3f& c) +{ + // Edges + Vec3f ab = b - a; + Vec3f ac = c - a; + Vec3f ap = p - a; + + auto d1 = dot(ab, ap); + auto d2 = dot(ac, ap); + if (d1 <= T(0.0) && d2 <= T(0.0)) { + return dot(ap, ap); // barycentric (1,0,0) + } + + Vec3f bp = p - b; + auto d3 = dot(ab, bp); + auto d4 = dot(ac, bp); + if (d3 >= T(0.0) && d4 <= d3) { + return dot(bp, bp); // (0,1,0) + } + + T vc = d1 * d4 - d3 * d2; + if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f) { + T v = d1 / (d1 - d3); + Vec3f proj = {a.x + v * ab.x, a.y + v * ab.y, a.z + v * ab.z}; + Vec3f d = p - proj; + return dot(d, d); // edge AB + } + + Vec3f cp = p - c; + T d5 = dot(ab, cp); + T d6 = dot(ac, cp); + if (d6 >= T(0.0f) && d5 <= d6) { + return dot(cp, cp); // (0,0,1) + } + + T vb = d5 * d2 - d1 * d6; + if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f) { + T w = d2 / (d2 - d6); + Vec3f proj = {a.x + w * ac.x, a.y + w * ac.y, a.z + w * ac.z}; + Vec3f d = p - proj; + return dot(d, d); // edge AC + } + + T va = d3 * d6 - d5 * d4; + if (va <= 0.0f && (d4 - d3) >= 0.0f && (d5 - d6) >= 0.0f) { + T w = (d4 - d3) / ((d4 - d3) + (d5 - d6)); + Vec3f proj = {b.x + w * (c.x - b.x), b.y + w * (c.y - b.y), b.z + w * (c.z - b.z)}; + Vec3f d = p - proj; + return dot(d, d); // edge BC + } + + // Inside face region + T denom = T(1.0f) / (va + vb + vc); + T v = vb * denom; + T w = vc * denom; + + Vec3f proj = {a.x + ab.x * v + ac.x * w, a.y + ab.y * v + ac.y * w, a.z + ab.z * v + ac.z * w}; + + Vec3f d = p - proj; + return dot(d, d); +} + +template +inline Vec3f normalize(const Vec3f& v) +{ + T len2 = dot(v, v); + if (len2 == T(0.0f)) { + std::cerr << "Degnerate triangle. Cannot determine normal"; + return {0, 0, 0}; + } + T invLen = T(1.0f) / std::sqrt(len2); + return {v.x * invLen, v.y * invLen, v.z * invLen}; +} + +template +inline Vec3f triangleNormal(const Vec3f& a, const Vec3f& b, const Vec3f& c) +{ + const Vec3f e1 = b - a; + const Vec3f e2 = c - a; + return normalize(cross(e1, e2)); +} + +} // end anonymous namespace + +//////////////////////////////////////////////////////////////////////////////// +/// DistFromOutside + +Double_t O2Tessellated::DistFromOutside(const Double_t* point, const Double_t* dir, Int_t /*iact*/, Double_t stepmax, + Double_t* /*safe*/) const +{ + // use the BVH intersector in combination with leaf ray-triangle testing + double local_step = Big(); // we need this otherwise the lambda get's confused + + using Scalar = float; + using Vec3 = bvh::v2::Vec; + using Node = bvh::v2::Node; + using Bvh = bvh::v2::Bvh; + using Ray = bvh::v2::Ray; + + // let's fetch the bvh + auto mybvh = (Bvh*)fBVH; + if (!mybvh) { + assert(false); + return -1.; + } + + auto truncate_roundup = [](double orig) { + float epsilon = std::numeric_limits::epsilon() * std::fabs(orig); + // Add the bias to x before assigning it to y + return static_cast(orig + epsilon); + }; + + // let's do very quick checks against the top node + const auto topnode_bbox = mybvh->get_root().get_bbox(); + if ((-point[0] + topnode_bbox.min[0]) > stepmax) { + return Big(); + } + if ((-point[1] + topnode_bbox.min[1]) > stepmax) { + return Big(); + } + if ((-point[2] + topnode_bbox.min[2]) > stepmax) { + return Big(); + } + if ((point[0] - topnode_bbox.max[0]) > stepmax) { + return Big(); + } + if ((point[1] - topnode_bbox.max[1]) > stepmax) { + return Big(); + } + if ((point[2] - topnode_bbox.max[2]) > stepmax) { + return Big(); + } + + // the ray used for bvh interaction + Ray ray(Vec3(point[0], point[1], point[2]), // origin + Vec3(dir[0], dir[1], dir[2]), // direction + 0.0f, // minimum distance (could give stepmax ?) + truncate_roundup(local_step)); + + static constexpr bool use_robust_traversal = true; + + Vertex_t dir_v{dir[0], dir[1], dir[2]}; + // Traverse the BVH and apply concrete object intersection in BVH leafs + bvh::v2::GrowingStack stack; + mybvh->intersect(ray, mybvh->get_root().index, stack, [&](size_t begin, size_t end) { + for (size_t prim_id = begin; prim_id < end; ++prim_id) { + auto objectid = mybvh->prim_ids[prim_id]; + const auto& facet = fFacets[objectid]; + const auto& n = fOutwardNormals[objectid]; + + // quick normal test. Coming from outside, the dot product must be negative + if (n.Dot(dir_v) > 0.) { + continue; + } + + auto thisdist = rayTriangle(Vertex_t(point[0], point[1], point[2]), dir_v, + fVertices[facet[0]], fVertices[facet[1]], fVertices[facet[2]], 0.); + + if (thisdist < local_step) { + local_step = thisdist; + } + } + return false; // go on after this + }); + + return local_step; +} + +//////////////////////////////////////////////////////////////////////////////// +/// DistFromOutside + +Double_t O2Tessellated::DistFromInside(const Double_t* point, const Double_t* dir, Int_t /*iact*/, Double_t /*stepmax*/, + Double_t* /*safe*/) const +{ + // use the BVH intersector in combination with leaf ray-triangle testing + double local_step = Big(); // we need this otherwise the lambda get's confused + + using Scalar = float; + using Vec3 = bvh::v2::Vec; + using Node = bvh::v2::Node; + using Bvh = bvh::v2::Bvh; + using Ray = bvh::v2::Ray; + + // let's fetch the bvh + auto mybvh = (Bvh*)fBVH; + if (!mybvh) { + assert(false); + return -1.; + } + + auto truncate_roundup = [](double orig) { + float epsilon = std::numeric_limits::epsilon() * std::fabs(orig); + // Add the bias to x before assigning it to y + return static_cast(orig + epsilon); + }; + + // the ray used for bvh interaction + Ray ray(Vec3(point[0], point[1], point[2]), // origin + Vec3(dir[0], dir[1], dir[2]), // direction + 0., // minimum distance (could give stepmax ?) + truncate_roundup(local_step)); + + static constexpr bool use_robust_traversal = true; + + Vertex_t dir_v{dir[0], dir[1], dir[2]}; + // Traverse the BVH and apply concrete object intersection in BVH leafs + bvh::v2::GrowingStack stack; + mybvh->intersect(ray, mybvh->get_root().index, stack, [&](size_t begin, size_t end) { + for (size_t prim_id = begin; prim_id < end; ++prim_id) { + auto objectid = mybvh->prim_ids[prim_id]; + auto facet = fFacets[objectid]; + const auto& n = fOutwardNormals[objectid]; + + // Only exiting surfaces are relevant (from inside--> dot product must be positive) + if (n.Dot(dir_v) <= 0.) { + continue; + } + + const auto& v0 = fVertices[facet[0]]; + const auto& v1 = fVertices[facet[1]]; + const auto& v2 = fVertices[facet[2]]; + + const double t = + rayTriangle(Vertex_t{point[0], point[1], point[2]}, dir_v, v0, v1, v2, 0.); + if (t < local_step) { + local_step = t; + } + } + return false; // go on after this + }); + + return local_step; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Capacity + +Double_t O2Tessellated::Capacity() const +{ + // For explanation of the following algorithm see: + // https://en.wikipedia.org/wiki/Polyhedron#Volume + // http://wwwf.imperial.ac.uk/~rn/centroid.pdf + + double vol = 0.0; + for (size_t i = 0; i < fFacets.size(); ++i) { + auto& facet = fFacets[i]; + auto a = fVertices[facet[0]]; + auto b = fVertices[facet[1]]; + auto c = fVertices[facet[2]]; + vol += + a[0] * (b[1] * c[2] - b[2] * c[1]) + b[0] * (c[1] * a[2] - c[2] * a[1]) + c[0] * (a[1] * b[2] - a[2] * b[1]); + } + return vol / 6.0; +} + +//////////////////////////////////////////////////////////////////////////////// +/// BuildBVH + +void O2Tessellated::BuildBVH() +{ + using Scalar = float; + using BBox = bvh::v2::BBox; + using Vec3 = bvh::v2::Vec; + using Node = bvh::v2::Node; + using Bvh = bvh::v2::Bvh; + + // helper determining axis aligned bounding box from a facet; + auto GetBoundingBox = [this](TGeoFacet const& facet) { +#ifndef NDEBUG + const auto nvertices = facet.GetNvert(); + assert(nvertices == 3); // for now only triangles +#endif + const auto& v1 = fVertices[facet[0]]; + const auto& v2 = fVertices[facet[1]]; + const auto& v3 = fVertices[facet[2]]; + BBox bbox; + bbox.min[0] = std::min(std::min(v1[0], v2[0]), v3[0]) - 0.001f; + bbox.min[1] = std::min(std::min(v1[1], v2[1]), v3[1]) - 0.001f; + bbox.min[2] = std::min(std::min(v1[2], v2[2]), v3[2]) - 0.001f; + bbox.max[0] = std::max(std::max(v1[0], v2[0]), v3[0]) + 0.001f; + bbox.max[1] = std::max(std::max(v1[1], v2[1]), v3[1]) + 0.001f; + bbox.max[2] = std::max(std::max(v1[2], v2[2]), v3[2]) + 0.001f; + return bbox; + }; + + // we need bounding boxes enclosing the primitives and centers of primitives + // (replaced here by centers of bounding boxes) to build the bvh + std::vector bboxes; + std::vector centers; + + // loop over all the triangles/Facets; + int nd = fFacets.size(); + for (int i = 0; i < nd; ++i) { + auto& facet = fFacets[i]; + + // fetch the bounding box of this node and add to the vector of bounding boxes + (bboxes).push_back(GetBoundingBox(facet)); + centers.emplace_back((bboxes).back().get_center()); + } + + // check if some previous object is registered and delete if necessary + if (fBVH) { + delete (Bvh*)fBVH; + fBVH = nullptr; + } + + // create the bvh + typename bvh::v2::DefaultBuilder::Config config; + config.quality = bvh::v2::DefaultBuilder::Quality::High; + auto bvh = bvh::v2::DefaultBuilder::build(bboxes, centers, config); + auto bvhptr = new Bvh; + *bvhptr = std::move(bvh); // copy structure + fBVH = (void*)(bvhptr); + + return; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Contains + +bool O2Tessellated::Contains(Double_t const* point) const +{ + // we do the parity test + using Scalar = float; + using Vec3 = bvh::v2::Vec; + using Node = bvh::v2::Node; + using Bvh = bvh::v2::Bvh; + using Ray = bvh::v2::Ray; + + // let's fetch the bvh + auto mybvh = (Bvh*)fBVH; + if (!mybvh) { + assert(false); + return false; + } + + auto truncate_roundup = [](double orig) { + float epsilon = std::numeric_limits::epsilon() * std::fabs(orig); + // Add the bias to x before assigning it to y + return static_cast(orig + epsilon); + }; + + // let's do very quick checks against the top node + if (!TGeoBBox::Contains(point)) { + return false; + } + + // An arbitrary test direction. + // Doesn't need to be normalized and probes all normals. Also ensuring to be skewed somewhat + // without evident symmetries. + Vertex_t test_dir{1.0, 1.41421356237, 1.73205080757}; + + double local_step = Big(); + // the ray used for bvh interaction + Ray ray(Vec3(point[0], point[1], point[2]), // origin + Vec3(test_dir[0], test_dir[1], test_dir[2]), // direction + 0.0f, // minimum distance (could give stepmax ?) + truncate_roundup(local_step)); + + static constexpr bool use_robust_traversal = true; + + // Traverse the BVH and apply concrete object intersection in BVH leafs + bvh::v2::GrowingStack stack; + size_t crossings = 0; + mybvh->intersect(ray, mybvh->get_root().index, stack, [&](size_t begin, size_t end) { + for (size_t prim_id = begin; prim_id < end; ++prim_id) { + auto objectid = mybvh->prim_ids[prim_id]; + auto& facet = fFacets[objectid]; + + // for the parity test, we probe all crossing surfaces + const auto& v0 = fVertices[facet[0]]; + const auto& v1 = fVertices[facet[1]]; + const auto& v2 = fVertices[facet[2]]; + + const double t = rayTriangle(Vertex_t(point[0], point[1], point[2]), + test_dir, v0, v1, v2, 0.); + + if (t != std::numeric_limits::infinity()) { + ++crossings; + } + } + return false; + }); + + return crossings & 1; +} + +namespace +{ + +// Helper classes/structs used for priority queue - BVH traversal +// structure keeping cost (value) for a BVH index +struct BVHPrioElement { + size_t bvh_node_id; + float value; +}; + +// A priority queue for BVHPrioElement with an additional clear method +// for quick reset. We intentionally derive from std::priority_queue here to expose a +// clear() convenience method via access to the protected container `c`. +// This is internal, non-polymorphic code and relies on standard-library +// implementation details that are stable across supported platforms. +template +class BVHPrioQueue : public std::priority_queue, Comparator> +{ + public: + using std::priority_queue, + Comparator>::priority_queue; // constructor inclusion + + // convenience method to quickly clear/reset the queue (instead of having to pop one by one) + void clear() { this->c.clear(); } +}; + +} // namespace + +/// a reusable safety kernel, which optionally returns the closest face +template +inline Double_t O2Tessellated::SafetyKernel(const Double_t* point, bool in, int* closest_facet_id) const +{ + // This is the classic traversal/pruning of a BVH based on priority queue search + + float smallest_safety_sq = TGeoShape::Big(); + + using Scalar = float; + using Vec3 = bvh::v2::Vec; + using Node = bvh::v2::Node; + using Bvh = bvh::v2::Bvh; + + // let's fetch the bvh + auto mybvh = (Bvh*)fBVH; + + // testpoint object in float for quick BVH interaction + Vec3 testpoint(point[0], point[1], point[2]); + + auto currnode = mybvh->nodes[0]; // we start from the top BVH node + // we do a quick check on the top node (in case we are outside shape) + bool outside_top = false; + if (!in) { + outside_top = !bvh::v2::extra::contains(currnode.get_bbox(), testpoint); + if (outside_top) { + const auto safety_sq_to_top = bvh::v2::extra::SafetySqToNode(currnode.get_bbox(), testpoint); + // we simply return safety to the outer bounding box as an estimate + return std::sqrt(safety_sq_to_top); + } + } + + // comparator bringing out "smallest" value on top + auto cmp = [](BVHPrioElement a, BVHPrioElement b) { return a.value > b.value; }; + static thread_local BVHPrioQueue queue(cmp); + queue.clear(); + + // algorithm is based on standard iterative tree traversal with priority queues + float current_safety_to_node_sq = 0.f; + + if (returnFace) { + *closest_facet_id = -1; + } + + do { + if (currnode.is_leaf()) { + // we are in a leaf node and actually talk to a face/triangular primitive + const auto begin_prim_id = currnode.index.first_id(); + const auto end_prim_id = begin_prim_id + currnode.index.prim_count(); + + for (auto p_id = begin_prim_id; p_id < end_prim_id; p_id++) { + const auto object_id = mybvh->prim_ids[p_id]; + + const auto& facet = fFacets[object_id]; + const auto& v1 = fVertices[facet[0]]; + const auto& v2 = fVertices[facet[1]]; + const auto& v3 = fVertices[facet[2]]; + + auto thissafetySQ = pointTriangleDistSq(Vec3f{point[0], point[1], point[2]}, Vec3f{v1[0], v1[1], v1[2]}, + Vec3f{v2[0], v2[1], v2[2]}, Vec3f{v3[0], v3[1], v3[2]}); + + if (thissafetySQ < smallest_safety_sq) { + smallest_safety_sq = thissafetySQ; + if (returnFace) { + *closest_facet_id = object_id; + } + } + } + } else { + // not a leave node ... for further traversal, + // we inject the children into priority queue based on distance to it's bounding box + const auto leftchild_id = currnode.index.first_id(); + const auto rightchild_id = leftchild_id + 1; + + for (size_t childid : {leftchild_id, rightchild_id}) { + if (childid >= mybvh->nodes.size()) { + continue; + } + + const auto& node = mybvh->nodes[childid]; + const auto inside = bvh::v2::extra::contains(node.get_bbox(), testpoint); + + if (inside) { + // this must be further considered because we are inside the bounding box + queue.push(BVHPrioElement{childid, -1.}); + } else { + auto safety_to_node_square = bvh::v2::extra::SafetySqToNode(node.get_bbox(), testpoint); + if (safety_to_node_square <= smallest_safety_sq) { + // this should be further considered + queue.push(BVHPrioElement{childid, safety_to_node_square}); + } + } + } + } + + if (queue.size() > 0) { + auto currElement = queue.top(); + currnode = mybvh->nodes[currElement.bvh_node_id]; + current_safety_to_node_sq = currElement.value; + queue.pop(); + } else { + break; + } + } while (current_safety_to_node_sq <= smallest_safety_sq); + + return std::nextafter(std::sqrt(smallest_safety_sq), 0.0f); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Safety + +Double_t O2Tessellated::Safety(const Double_t* point, Bool_t in) const +{ + // we could use some caching here (in future) since queries to the solid will likely + // be made with some locality + + // fall-back to precise safety kernel + return SafetyKernel(point, in); +} + +//////////////////////////////////////////////////////////////////////////////// +/// ComputeNormal interface + +void O2Tessellated::ComputeNormal(const Double_t* point, const Double_t* dir, Double_t* norm) const +{ + // We take the approach to identify closest facet to the point via safety + // and returning the normal from this face. + + // TODO: Before doing that we could check for cached points from other queries + + // use safety kernel + int closest_face_id = -1; + SafetyKernel(point, true, &closest_face_id); + + if (closest_face_id < 0) { + norm[0] = 1.; + norm[1] = 0.; + norm[2] = 0.; + return; + } + + const auto& n = fOutwardNormals[closest_face_id]; + norm[0] = n[0]; + norm[1] = n[1]; + norm[2] = n[2]; + + // change sign depending on dir + if (norm[0] * dir[0] + norm[1] * dir[1] + norm[2] * dir[2] < 0) { + norm[0] = -norm[0]; + norm[1] = -norm[1]; + norm[2] = -norm[2]; + } + return; +} + +//////////////////////////////////////////////////////////////////////////////// +/// trivial (non-BVH) DistFromInside function + +Double_t O2Tessellated::DistFromInside_Loop(const Double_t* point, const Double_t* dir) const +{ + Vertex_t p(point[0], point[1], point[2]); + Vertex_t d(dir[0], dir[1], dir[2]); + + double dist = Big(); + for (size_t i = 0; i < fFacets.size(); ++i) { + const auto& facet = fFacets[i]; + const auto& n = fOutwardNormals[i]; + + // Only exiting surfaces are relevant (from inside--> dot product must be positive) + if (n.Dot(d) <= 0.0) { + continue; + } + + const auto& v0 = fVertices[facet[0]]; + const auto& v1 = fVertices[facet[1]]; + const auto& v2 = fVertices[facet[2]]; + + const double t = rayTriangle(p, d, v0, v1, v2, 0.); + + if (t < dist) { + dist = t; + } + } + return dist; +} + +//////////////////////////////////////////////////////////////////////////////// +/// trivial (non-BVH) DistFromOutside function + +Double_t O2Tessellated::DistFromOutside_Loop(const Double_t* point, const Double_t* dir) const +{ + Vertex_t p(point[0], point[1], point[2]); + Vertex_t d(dir[0], dir[1], dir[2]); + + double dist = Big(); + for (size_t i = 0; i < fFacets.size(); ++i) { + const auto& facet = fFacets[i]; + const auto& n = fOutwardNormals[i]; + + // Only exiting surfaces are relevant (from outside, the dot product must be negative) + if (n.Dot(d) > 0.0) { + continue; + } + + const auto& v0 = fVertices[facet[0]]; + const auto& v1 = fVertices[facet[1]]; + const auto& v2 = fVertices[facet[2]]; + + const double t = rayTriangle(p, d, v0, v1, v2, 0.); + + if (t < dist) { + dist = t; + } + } + return dist; +} + +//////////////////////////////////////////////////////////////////////////////// +/// trivial (non-BVH) Contains + +bool O2Tessellated::Contains_Loop(const Double_t* point) const +{ + // Fixed ray direction + const Vertex_t test_dir{1.0, 1.41421356237, 1.73205080757}; + + Vertex_t p(point[0], point[1], point[2]); + + int crossings = 0; + for (size_t i = 0; i < fFacets.size(); ++i) { + const auto& facet = fFacets[i]; + + const auto& v0 = fVertices[facet[0]]; + const auto& v1 = fVertices[facet[1]]; + const auto& v2 = fVertices[facet[2]]; + + const double t = rayTriangle(p, test_dir, v0, v1, v2, 0.); + if (t != std::numeric_limits::infinity()) { + ++crossings; + } + } + return (crossings & 1); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Custom streamer which performs Closing on read. +/// Recalculation of BVH and normals is fast + +void O2Tessellated::Streamer(TBuffer& b) +{ + if (b.IsReading()) { + b.ReadClassBuffer(O2Tessellated::Class(), this); + CloseShape(false); // close shape but do not re-perform checks + } else { + b.WriteClassBuffer(O2Tessellated::Class(), this); + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Calculate the normals + +void O2Tessellated::CalculateNormals() +{ + fOutwardNormals.clear(); + for (auto& facet : fFacets) { + auto& v1 = fVertices[facet[0]]; + auto& v2 = fVertices[facet[1]]; + auto& v3 = fVertices[facet[2]]; + using Vec3d = Vec3f; + auto norm = triangleNormal(Vec3d{v1[0], v1[1], v1[2]}, Vec3d{v2[0], v2[1], v2[2]}, Vec3d{v3[0], v3[1], v3[2]}); + fOutwardNormals.emplace_back(Vertex_t{norm.x, norm.y, norm.z}); + } +} + +// NOLINTEND \ No newline at end of file diff --git a/Detectors/Base/src/TGeoGeometryUtils.cxx b/Detectors/Base/src/TGeoGeometryUtils.cxx new file mode 100644 index 0000000000000..6f06eff17a6d7 --- /dev/null +++ b/Detectors/Base/src/TGeoGeometryUtils.cxx @@ -0,0 +1,144 @@ +// 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 TGeoGeometryUtils.cxx +/// \author Sandro Wenzel (CERN) +/// \brief Collection of utility functions for TGeo + +#include +#include +#include +#include +#include + +namespace o2 +{ +namespace base +{ + +namespace +{ +// some helpers to interpret TGeo TBuffer3D output +// and convert it to surface triangles (reengineered from TGeo code) + +std::vector BuildVertexLoop(const TBuffer3D& buf, + const std::vector& segs) +{ + // adjacency list + std::unordered_map> adj; + + for (int s : segs) { + int a = buf.fSegs[3 * s + 1]; + int b = buf.fSegs[3 * s + 2]; + adj[a].push_back(b); + adj[b].push_back(a); + } + + // start from any vertex + int start = adj.begin()->first; + int prev = -1; + int curr = start; + + std::vector loop; + + while (true) { + loop.push_back(curr); + + const auto& nbrs = adj[curr]; + int next = -1; + + for (int n : nbrs) { + if (n != prev) { + next = n; + break; + } + } + + if (next == -1 || next == start) { + break; + } + + prev = curr; + curr = next; + } + return loop; +} + +std::vector> ExtractPolygons(const TBuffer3D& buf) +{ + std::vector> polys; + Int_t idx = 0; + + for (Int_t ip = 0; ip < buf.NbPols(); ++ip) { + + idx++; // color + Int_t nseg = buf.fPols[idx++]; + + std::vector segs(nseg); + for (Int_t i = 0; i < nseg; ++i) { + segs[i] = buf.fPols[idx++]; + } + + auto verts = BuildVertexLoop(buf, segs); + if (verts.size() >= 3) { + polys.push_back(std::move(verts)); + } + } + + return polys; +} + +std::vector> + Triangulate(const std::vector>& polys) +{ + std::vector> tris; + for (const auto& poly : polys) { + int nv = poly.size(); + if (nv < 3) { + continue; + } + + int v0 = poly[0]; + for (int i = 1; i < nv - 1; ++i) { + tris.push_back({{v0, poly[i], poly[i + 1]}}); + } + } + return tris; +} + +TGeoTessellated* MakeTessellated(const TBuffer3D& buf) +{ + auto polys = ExtractPolygons(buf); + auto tris = Triangulate(polys); + int i = 0; + auto* tess = new TGeoTessellated("tess"); + const Double_t* p = buf.fPnts; + for (auto& t : tris) { + tess->AddFacet( + TGeoTessellated::Vertex_t{p[3 * t[0]], p[3 * t[0] + 1], p[3 * t[0] + 2]}, + TGeoTessellated::Vertex_t{p[3 * t[1]], p[3 * t[1] + 1], p[3 * t[1] + 2]}, + TGeoTessellated::Vertex_t{p[3 * t[2]], p[3 * t[2] + 1], p[3 * t[2] + 2]}); + } + tess->CloseShape(); + return tess; +} +} // end anonymous namespace + +///< Transform any (primitive) TGeoShape to a TGeoTessellated +TGeoTessellated* TGeoGeometryUtils::TGeoShapeToTGeoTessellated(TGeoShape const* shape) +{ + auto& buf = shape->GetBuffer3D(TBuffer3D::kRawSizes | TBuffer3D::kRaw | TBuffer3D::kCore, false); + auto tes = MakeTessellated(buf); + return tes; +} + +} // namespace base +} // namespace o2 diff --git a/Detectors/Base/src/bvh2_extra_kernels.h b/Detectors/Base/src/bvh2_extra_kernels.h new file mode 100644 index 0000000000000..70e43202a53c4 --- /dev/null +++ b/Detectors/Base/src/bvh2_extra_kernels.h @@ -0,0 +1,79 @@ +// 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. + +// Sandro Wenzel 2026 + +#ifndef ROOT_GEOM_BVH2_EXTRA + +namespace bvh::v2::extra +{ + +// reusable geometry kernels used in multiple places +// for interaction with BVH2 structures + +// determines if a point is inside the bounding box +template +bool contains(bvh::v2::BBox const& box, bvh::v2::Vec const& p) +{ + auto min = box.min; + auto max = box.max; + return (p[0] >= min[0] && p[0] <= max[0]) && (p[1] >= min[1] && p[1] <= max[1]) && + (p[2] >= min[2] && p[2] <= max[2]); +} + +// determines the largest squared distance of point to any of the bounding box corners +template +auto RmaxSqToNode(bvh::v2::BBox const& box, bvh::v2::Vec const& p) +{ + // construct the 8 corners to get the maximal distance + const auto minCorner = box.min; + const auto maxCorner = box.max; + using Vec3 = bvh::v2::Vec; + // these are the corners of the bounding box + const std::array, 8> corners{ + Vec3{minCorner[0], minCorner[1], minCorner[2]}, Vec3{minCorner[0], minCorner[1], maxCorner[2]}, + Vec3{minCorner[0], maxCorner[1], minCorner[2]}, Vec3{minCorner[0], maxCorner[1], maxCorner[2]}, + Vec3{maxCorner[0], minCorner[1], minCorner[2]}, Vec3{maxCorner[0], minCorner[1], maxCorner[2]}, + Vec3{maxCorner[0], maxCorner[1], minCorner[2]}, Vec3{maxCorner[0], maxCorner[1], maxCorner[2]}}; + + T Rmax_sq{0}; + for (const auto& corner : corners) { + float R_sq = 0.; + const auto dx = corner[0] - p[0]; + R_sq += dx * dx; + const auto dy = corner[1] - p[1]; + R_sq += dy * dy; + const auto dz = corner[2] - p[2]; + R_sq += dz * dz; + Rmax_sq = std::max(Rmax_sq, R_sq); + } + return Rmax_sq; +}; + +// determines the minimum squared distance of point to a bounding box ("safey square") +template +auto SafetySqToNode(bvh::v2::BBox const& box, bvh::v2::Vec const& p) +{ + T sqDist{0.0}; + for (int i = 0; i < 3; i++) { + T v = p[i]; + if (v < box.min[i]) { + sqDist += (box.min[i] - v) * (box.min[i] - v); + } else if (v > box.max[i]) { + sqDist += (v - box.max[i]) * (v - box.max[i]); + } + } + return sqDist; +}; + +} // namespace bvh::v2::extra + +#endif \ No newline at end of file diff --git a/Detectors/Base/src/bvh2_third_party.h b/Detectors/Base/src/bvh2_third_party.h new file mode 100644 index 0000000000000..5cf7772269642 --- /dev/null +++ b/Detectors/Base/src/bvh2_third_party.h @@ -0,0 +1,49 @@ +// 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. + +// Sandro Wenzel 2026 + +#ifndef ROOT_GEOM_BVH2_THIRD_PARTY + +// A single entry header into third-party BVH2 installed in ROOT +// Good place to manage compiler warnings etc. + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wshadow" +#pragma clang diagnostic ignored "-Wpsabi" +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wpsabi" +#pragma GCC diagnostic ignored "-Wall" +#pragma GCC diagnostic ignored "-Wshadow" +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC diagnostic ignored "-Wattributes" +#elif defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 5051) +#endif + +#include +#include +#include +#include +#include +#include + +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#endif \ No newline at end of file diff --git a/Detectors/Passive/CMakeLists.txt b/Detectors/Passive/CMakeLists.txt index 0976530bc6571..a24954ad10539 100644 --- a/Detectors/Passive/CMakeLists.txt +++ b/Detectors/Passive/CMakeLists.txt @@ -23,6 +23,7 @@ o2_add_library(DetectorsPassive src/Hall.cxx src/HallSimParam.cxx src/PassiveBase.cxx + src/ExternalModule.cxx PUBLIC_LINK_LIBRARIES O2::Field O2::DetectorsBase O2::SimConfig) o2_target_root_dictionary(DetectorsPassive @@ -39,6 +40,7 @@ o2_target_root_dictionary(DetectorsPassive include/DetectorsPassive/Hall.h include/DetectorsPassive/HallSimParam.h include/DetectorsPassive/PassiveBase.h + include/DetectorsPassive/ExternalModule.h LINKDEF src/PassiveLinkDef.h) # FIXME: if PutFrameInTop really depends on TRD, then the following can not work diff --git a/Detectors/Passive/include/DetectorsPassive/ExternalModule.h b/Detectors/Passive/include/DetectorsPassive/ExternalModule.h new file mode 100644 index 0000000000000..155870ae42a6d --- /dev/null +++ b/Detectors/Passive/include/DetectorsPassive/ExternalModule.h @@ -0,0 +1,64 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef ALICEO2_PASSIVE_EXTERNALMODULE_H +#define ALICEO2_PASSIVE_EXTERNALMODULE_H + +#include "DetectorsPassive/PassiveBase.h" // base class of passive modules +#include "Rtypes.h" // for Pipe::Class, ClassDef, Pipe::Streamer + +class TGeoVolume; +class TGeoTransformation; + +namespace o2 +{ +namespace passive +{ + +// options used to configure a generic plug and play external module +struct ExternalModuleOptions { + std::string root_macro_file; // the file where to lookup the ROOT geometry building macro + std::string top_volume; // the volume to be added + std::string anchor_volume; // the volume into which the detector will be hooked + TGeoMatrix const* placement = nullptr; // how to place the module inside anchor_volume +}; + +// a module (passive material) defined externally (ROOT macro / GDML / TGeo geometry) +class ExternalModule : public PassiveBase +{ + public: + ExternalModule(const char* name, const char* long_title, ExternalModuleOptions options); + ExternalModule() = default; // default constructor + + ~ExternalModule() override = default; + void ConstructGeometry() override; + + /// Clone this object (used in MT mode only) + FairModule* CloneModule() const override { return nullptr; } + + typedef std::function GeomBuilderFcn; // function hook for external geometry builder + + private: + // void createMaterials(); + ExternalModule(const ExternalModule& orig); + ExternalModule& operator=(const ExternalModule&); + + GeomBuilderFcn mGeomHook; + ExternalModuleOptions mOptions; + + bool initGeomBuilderHook(); // function to load/JIT Geometry builder hook + void remapMedia(TGeoVolume* vol); // performs a remapping of materials/media IDs after registration with VMC + + // ClassDefOverride(ExternalModule, 0); +}; +} // namespace passive +} // namespace o2 +#endif diff --git a/Detectors/Passive/src/ExternalModule.cxx b/Detectors/Passive/src/ExternalModule.cxx new file mode 100644 index 0000000000000..fc6bd6953b82d --- /dev/null +++ b/Detectors/Passive/src/ExternalModule.cxx @@ -0,0 +1,175 @@ +// 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. + +// Sandro Wenzel (CERN), 2026 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// ClassImp(o2::passive::ExternalModule) + +namespace o2::passive +{ + +ExternalModule::ExternalModule(const char* name, const char* long_title, ExternalModuleOptions options) : PassiveBase(name, long_title), mOptions(options) +{ +} + +void ExternalModule::remapMedia(TGeoVolume* top_volume) +{ + std::unordered_map medium_ptr_mapping; + std::unordered_set volumes_already_treated; + int counter = 1; + + auto modulename = GetName(); + + // The transformer function + auto transform_media = [&](TGeoVolume* vol_) { + if (volumes_already_treated.find(vol_) != volumes_already_treated.end()) { + // this volume was already transformed + return; + } + volumes_already_treated.insert(vol_); + + if (dynamic_cast(vol_)) { + // do nothing for assemblies (they don't have a medium) + return; + } + + auto medium = vol_->GetMedium(); + if (!medium) { + return; + } + + auto iter = medium_ptr_mapping.find(medium); + if (iter != medium_ptr_mapping.end()) { + // This medium has already been transformed, so + // we just update the volume + vol_->SetMedium(iter->second); + return; + } else { + std::cout << "Transforming media with name " << medium->GetName() << " for volume " << vol_->GetName() << "\n"; + + // we found a medium, not yet treated + auto curr_mat = medium->GetMaterial(); + auto& matmgr = o2::base::MaterialManager::Instance(); + + matmgr.Material(modulename, counter, curr_mat->GetName(), curr_mat->GetA(), curr_mat->GetZ(), curr_mat->GetDensity(), curr_mat->GetRadLen(), curr_mat->GetIntLen()); + // TGeo medium params are stored in a flat array with the following convention + // fParams[0] = isvol; + // fParams[1] = ifield; + // fParams[2] = fieldm; + // fParams[3] = tmaxfd; + // fParams[4] = stemax; + // fParams[5] = deemax; + // fParams[6] = epsil; + // fParams[7] = stmin; + const auto isvol = medium->GetParam(0); + const auto isxfld = medium->GetParam(1); + const auto sxmgmx = medium->GetParam(2); + const auto tmaxfd = medium->GetParam(3); + const auto stemax = medium->GetParam(4); + const auto deemax = medium->GetParam(5); + const auto epsil = medium->GetParam(6); + const auto stmin = medium->GetParam(7); + + matmgr.Medium(modulename, counter, medium->GetName(), counter, isvol, isxfld, sxmgmx, tmaxfd, stemax, deemax, epsil, stmin); + + // there will be new Material and Medium objects; fetch them + auto new_med = matmgr.getTGeoMedium(modulename, counter); + + // insert into cache + medium_ptr_mapping[medium] = new_med; + vol_->SetMedium(new_med); + counter++; + } + }; // end transformer lambda + + // a generic volume walker + std::function visit_volume; + visit_volume = [&](TGeoVolume* vol) -> void { + if (!vol) { + return; + } + + // call the transformer + transform_media(vol); + + // Recurse into daughters + const int nd = vol->GetNdaughters(); + for (int i = 0; i < nd; ++i) { + TGeoNode* node = vol->GetNode(i); + if (!node) { + continue; + } + TGeoVolume* child = node->GetVolume(); + if (!child) { + continue; + } + + visit_volume(child); + } + }; + + visit_volume(top_volume); +} + +void ExternalModule::ConstructGeometry() +{ + // JIT the geom builder hook + if (!initGeomBuilderHook()) { + LOG(error) << " Could not load geometry builder hook"; + return; + } + + // otherwise execute it and obtain pointer to top most module volume + auto module_top = mGeomHook(); + if (!module_top) { + LOG(error) << "No module found\n"; + return; + } + + remapMedia(const_cast(module_top)); + + // place it into the provided anchor volume (needs to exist) + auto anchor = gGeoManager->FindVolumeFast(mOptions.anchor_volume.c_str()); + if (!anchor) { + LOG(error) << "Anchor volume " << mOptions.anchor_volume << " not found. Aborting"; + return; + } + anchor->AddNode(const_cast(module_top), 1, const_cast(mOptions.placement)); +} + +bool ExternalModule::initGeomBuilderHook() +{ + if (mOptions.root_macro_file.size() > 0) { + LOG(info) << "Initializing the hook for geometry module building"; + auto expandedHookFileName = o2::utils::expandShellVarsInFileName(mOptions.root_macro_file); + if (std::filesystem::exists(expandedHookFileName)) { + // if this file exists we will compile the hook on the fly (the last one is an identifier --> maybe make it dependent on this class) + mGeomHook = o2::conf::GetFromMacro(mOptions.root_macro_file, "get_builder_hook_unchecked()", "function", "o2_passive_extmodule_builder"); + LOG(info) << "Hook initialized from file " << expandedHookFileName; + return true; + } + } + return false; +} + +} // namespace o2::passive \ No newline at end of file diff --git a/Steer/include/Steer/O2MCApplicationBase.h b/Steer/include/Steer/O2MCApplicationBase.h index 36966be9bde62..d61199baba0ae 100644 --- a/Steer/include/Steer/O2MCApplicationBase.h +++ b/Steer/include/Steer/O2MCApplicationBase.h @@ -58,6 +58,8 @@ class O2MCApplicationBase : public FairMCApplication typedef std::function TrackRefFcn; + void fixTGeoRuntimeShapes(); + protected: o2::conf::SimCutParams const& mCutParams; // reference to parameter system unsigned long long mStepCounter{0}; diff --git a/Steer/src/O2MCApplication.cxx b/Steer/src/O2MCApplication.cxx index 584598d350581..f832ab70ab121 100644 --- a/Steer/src/O2MCApplication.cxx +++ b/Steer/src/O2MCApplication.cxx @@ -37,6 +37,11 @@ #include "SimConfig/GlobalProcessCutSimParam.h" #include "DetectorsBase/GeometryManagerParam.h" #include +#include +#include +#include +#include +#include namespace o2 { @@ -209,10 +214,65 @@ bool O2MCApplicationBase::MisalignGeometry() gGeoManager->SetUseParallelWorldNav(true); } + // performs possible optimizations (shape replacements on the runtime geometry) + fixTGeoRuntimeShapes(); + // return original return value of misalignment procedure return true; } +void O2MCApplicationBase::fixTGeoRuntimeShapes() +{ + // Replace TGeo shapes by other ones for performance or other reasons. + // Should only affect runtime of simulation. + + // TODO: make this configurable via external JSON rules/macro + + // Also delete original shapes for memory reasons + + // We follow a visitor pattern on a geom hierarchy + // for now replace a TGeoTessellate by our own implementation + std::unordered_set volumes_visited; + std::unordered_set old_shape_pointers; + + std::function visit; + visit = [&](TGeoNode* node) -> void { + if (!node) { + return; + } + auto vol = node->GetVolume(); + if (volumes_visited.find(vol) != volumes_visited.end()) { + return; + } + volumes_visited.insert(vol); + + // transform the shape of this volume + auto shape = vol->GetShape(); + if (shape->IsA() == TGeoTessellated::Class()) { + auto tsl = static_cast(shape); + + // make a new O2Tessellated until ROOT has proper support for navigation in TGeoTessellated + std::cout << "Converting to O2Tessellated for vol " << vol->GetName() << "\n"; + auto replacement_shape = new o2::base::O2Tessellated(*tsl, false); + vol->SetShape(replacement_shape); + old_shape_pointers.insert(shape); + } + // other cases could come here + + for (int i = 0; i < vol->GetNdaughters(); ++i) { + auto child_node = vol->GetNode(i); + visit(child_node); + } + }; + + visit(gGeoManager->GetTopNode()); + + for (auto ptr : old_shape_pointers) { + delete ptr; + ptr = nullptr; + } +} + void O2MCApplicationBase::finishEventCommon() { LOG(info) << "This event/chunk did " << mStepCounter << " steps"; diff --git a/macro/build_geometry.C b/macro/build_geometry.C index 6b13f2eac2766..ccc3b13fe728d 100644 --- a/macro/build_geometry.C +++ b/macro/build_geometry.C @@ -63,6 +63,8 @@ #include #endif +#include + using Return = o2::base::Detector*; void finalize_geometry(FairRunSim* run); @@ -182,6 +184,18 @@ void build_geometry(FairRunSim* run = nullptr) } #endif + if (isActivated("EXT")) { + // EXAMPLE!! how to pick geometry generated from external (CAD) module via `O2_CADtoTGeo.py` + o2::passive::ExternalModuleOptions options; + options.root_macro_file = "PATH_TO_EXTERNAL_GEOM_MODULE/geom.C"; + options.anchor_volume = "barrel"; // hook this into barrel + auto rot = new TGeoCombiTrans(); + rot->RotateX(90); + rot->SetDy(30); // we need to compensate for a shift of barrel with respect to zero + options.placement = rot; + run->AddModule(new o2::passive::ExternalModule("FOO", "BAR", options)); + } + // the absorber if (isActivated("ABSO")) { // the frame structure to support other detectors diff --git a/scripts/geometry/O2_CADtoTGeo.py b/scripts/geometry/O2_CADtoTGeo.py new file mode 100644 index 0000000000000..d564cdc6124a8 --- /dev/null +++ b/scripts/geometry/O2_CADtoTGeo.py @@ -0,0 +1,602 @@ +#!/usr/bin/env python3 +""" +A Python script, doing a deep STEP/XCAF -> ROOT TGeo conversion. +For now, all CAD solids are simply meshed. The ROOT geometry is build as a C++ ROOT macro +and facet data is stored in binary form to keep disc space minimal. + +Generates (into --output-folder): + - geom.C (small ROOT macro) + - facets__.bin for each leaf logical volume (float32 triangles) + +Facet file format (little-endian): + uint32 nTriangles + then nTriangles * 9 * float32: + ax ay az bx by bz cx cy cz + +VOLNAME is a filename-safe version of the XCAF label name when available (e.g. "nut"), +and LID is the XCAF label entry (e.g. "0:1:1:7" -> "0_1_1_7") to keep filenames unique. + +Naming: + - C++ variable names stay based on XCAF label entry (e.g. 0:1:1:7) for uniqueness. + - ROOT object names (TGeoVolume / TGeoTessellated / TGeoVolumeAssembly) use the label's + human name when available (e.g. "nut", "rod-assembly"), falling back to the entry. + +Units: + - By default, the script tries to detect the STEP LENGTH unit by scanning the STEP file + header/contents (common patterns like .MILLI. / .CENTI. / .METRE. / INCH / FOOT). + - You can override with --step-unit {auto,mm,cm,m,in,ft}. TGeo expects cm. + +Author: + - Sandro Wenzel, CERN (02/2026) +""" + +import warnings +warnings.filterwarnings("ignore", message=".*all to deprecated function.*", category=DeprecationWarning) + +import argparse +import re +import struct +from pathlib import Path as _Path + +from OCC.Core.Bnd import Bnd_Box +from OCC.Core.BRepBndLib import brepbndlib +from OCC.Core.BRepMesh import BRepMesh_IncrementalMesh +from OCC.Core.BRep import BRep_Tool +from OCC.Core.TopLoc import TopLoc_Location +from OCC.Core.TopAbs import TopAbs_REVERSED +from OCC.Extend.TopologyUtils import TopologyExplorer + +from OCC.Core.STEPCAFControl import STEPCAFControl_Reader +from OCC.Core.TDocStd import TDocStd_Document +from OCC.Core.XCAFDoc import XCAFDoc_DocumentTool +from OCC.Core.IFSelect import IFSelect_RetDone + +from OCC.Core.TDF import TDF_Label, TDF_LabelSequence, TDF_Tool +from OCC.Core.TCollection import TCollection_AsciiString +from OCC.Core.gp import gp_Trsf + + +# ------------------------------- +# STEP/XCAF loading +# ------------------------------- + +def load_step_with_xcaf(path: str): + doc = TDocStd_Document("pythonocc-doc") + reader = STEPCAFControl_Reader() + reader.SetColorMode(True) + reader.SetNameMode(True) + reader.SetLayerMode(True) + + status = reader.ReadFile(path) + if status != IFSelect_RetDone: + raise RuntimeError(f"STEP read failed for: {path}") + + reader.Transfer(doc) + shape_tool = XCAFDoc_DocumentTool.ShapeTool(doc.Main()) + return doc, shape_tool + + +def label_id(label: TDF_Label) -> str: + s = TCollection_AsciiString() + TDF_Tool.Entry(label, s) + return s.ToCString() + + +def label_name(label: TDF_Label) -> str: + # Uses the XCAF/STEP name when present; can be empty. + try: + n = label.GetLabelName() + if n: + return str(n) + except Exception: + pass + return "" + + +# ------------------------------- +# Units +# ------------------------------- + +def step_unit_scale_to_cm(step_unit: str) -> float: + step_unit = (step_unit or "auto").lower() + if step_unit == "mm": + return 0.1 + if step_unit == "cm": + return 1.0 + if step_unit == "m": + return 100.0 + if step_unit == "in": + return 2.54 + if step_unit == "ft": + return 30.48 + raise ValueError(f"Unknown --step-unit {step_unit} (use auto, mm, cm, m, in, ft)") + + +def detect_step_length_unit(step_path: str) -> str: + """ + Heuristic unit detection by scanning STEP file text for common unit tokens. + This avoids relying on OCCT APIs that can vary across pythonOCC builds. + + Returns one of: mm, cm, m, in, ft. Defaults to mm if uncertain. + """ + p = _Path(step_path) + # STEP can be huge: read only the first few MB; units are near the header. + max_bytes = 4 * 1024 * 1024 + data = p.open("rb").read(max_bytes).decode("latin-1", errors="ignore").upper() + + if ".MILLI." in data: + return "mm" + if ".CENTI." in data: + return "cm" + if ".METRE." in data or ".METER." in data: + return "m" + if "INCH" in data: + return "in" + if "FOOT" in data or "FEET" in data: + return "ft" + + # Conservative default for mechanical CAD STEP is mm + return "mm" + + +# ------------------------------- +# Triangulation helpers +# ------------------------------- + +def _scale_triangles(triangles, s: float): + if s == 1.0: + return triangles + out = [] + for (a, b, c) in triangles: + out.append(( + (a[0] * s, a[1] * s, a[2] * s), + (b[0] * s, b[1] * s, b[2] * s), + (c[0] * s, c[1] * s, c[2] * s), + )) + return out + + +def triangulate_asbbox(shape, scale_to_cm: float = 1.0): + box = Bnd_Box() + brepbndlib.Add(shape, box) + xmin, ymin, zmin, xmax, ymax, zmax = box.Get() + + p000 = (xmin, ymin, zmin) + p001 = (xmin, ymin, zmax) + p010 = (xmin, ymax, zmin) + p011 = (xmin, ymax, zmax) + p100 = (xmax, ymin, zmin) + p101 = (xmax, ymin, zmax) + p110 = (xmax, ymax, zmin) + p111 = (xmax, ymax, zmax) + + triangles = [ + (p000, p100, p110), (p000, p110, p010), + (p001, p111, p101), (p001, p011, p111), + (p000, p101, p100), (p000, p001, p101), + (p010, p110, p111), (p010, p111, p011), + (p000, p010, p011), (p000, p011, p001), + (p100, p101, p111), (p100, p111, p110), + ] + return _scale_triangles(triangles, scale_to_cm) + + +def triangulate_CAD_solid(my_solid, meshparam, scale_to_cm: float = 1.0): + lin_defl = float(meshparam.get("lin_defl", 0.1)) + ang_defl = float(meshparam.get("ang_defl", 0.1)) + + parallel = True + try: + BRepMesh_IncrementalMesh(my_solid, lin_defl, False, ang_defl, bool(parallel)) + except TypeError: + BRepMesh_IncrementalMesh(my_solid, lin_defl, False, ang_defl) + + triangles = [] + for face in TopologyExplorer(my_solid).faces(): + loc = TopLoc_Location() + triangulation = BRep_Tool.Triangulation(face, loc) + if triangulation is None: + continue + + trsf = loc.Transformation() + reverse = (face.Orientation() == TopAbs_REVERSED) + + for i in range(1, triangulation.NbTriangles() + 1): + tri = triangulation.Triangle(i) + n1, n2, n3 = tri.Get() + + p1 = triangulation.Node(n1).Transformed(trsf) + p2 = triangulation.Node(n2).Transformed(trsf) + p3 = triangulation.Node(n3).Transformed(trsf) + + if reverse: + p2, p3 = p3, p2 + + triangles.append(( + (p1.X(), p1.Y(), p1.Z()), + (p2.X(), p2.Y(), p2.Z()), + (p3.X(), p3.Y(), p3.Z()), + )) + + return _scale_triangles(triangles, scale_to_cm) + + +# ------------------------------- +# Naming helpers +# ------------------------------- + +def sanitize_cpp_name(s: str) -> str: + safe = re.sub(r"[^0-9a-zA-Z]", "_", s) + if not safe: + safe = "x" + if not (safe[0].isalpha() or safe[0] == "_"): + safe = "_" + safe + return safe + + +def sanitize_filename(s: str) -> str: + safe = re.sub(r"[^0-9a-zA-Z]", "_", s) + return safe or "x" + + +# ------------------------------- +# Binary facet IO +# ------------------------------- + +def write_facets_bin(path: _Path, triangles): + path.parent.mkdir(parents=True, exist_ok=True) + with open(path, "wb") as f: + f.write(struct.pack(" str: + m = trsf.GetRotation().GetMatrix() + t = trsf.TranslationPart() + return f""" + Double_t {name}_m[9] = {{ + {m.Value(1,1)}, {m.Value(1,2)}, {m.Value(1,3)}, + {m.Value(2,1)}, {m.Value(2,2)}, {m.Value(2,3)}, + {m.Value(3,1)}, {m.Value(3,2)}, {m.Value(3,3)} + }}; + TGeoRotation *{name}_rot = new TGeoRotation(); + {name}_rot->SetMatrix({name}_m); + TGeoCombiTrans *{name} = new TGeoCombiTrans({t.X()*scale_to_cm}, {t.Y()*scale_to_cm}, {t.Z()*scale_to_cm}, {name}_rot); +""" + + +def emit_cpp_prelude() -> str: + return """#include +#include +#include +#include +#include +#include + +static void LoadFacets(const std::string& file, TGeoTessellated* solid, bool check=false) +{ + std::ifstream in(file, std::ios::binary); + if (!in) throw std::runtime_error("Cannot open facet file: " + file); + + uint32_t nTri = 0; + in.read(reinterpret_cast(&nTri), sizeof(nTri)); + if (!in) throw std::runtime_error("Bad facet header in: " + file); + + for (uint32_t i=0;i(v), sizeof(v)); + if (!in) throw std::runtime_error("Unexpected EOF in: " + file); + + solid->AddFacet(TGeoTessellated::Vertex_t(v[0],v[1],v[2]), + TGeoTessellated::Vertex_t(v[3],v[4],v[5]), + TGeoTessellated::Vertex_t(v[6],v[7],v[8])); + } + solid->CloseShape(check, true); +} +""" + + +def emit_materials_cpp() -> str: + return """ // Default material/medium (placeholder; can be replaced later) + TGeoMaterial *mat_Default = new TGeoMaterial("Default", 0., 0., 0.); + TGeoMedium *med_Default = new TGeoMedium("Default", 1, mat_Default); +""" + + +def emit_tessellated_cpp(lid: str, vol_display_name: str, facet_abspath: str, ntriangles: int) -> str: + safe = sanitize_cpp_name(lid) + shape_name = vol_display_name if vol_display_name else lid + + if ntriangles <= 0: + out = [] + out.append(f' TGeoBBox *solid_{safe} = new TGeoBBox("{shape_name}", 0.001, 0.001, 0.001);') + out.append(f' TGeoVolume *vol_{safe} = new TGeoVolume("{shape_name}", solid_{safe}, med_Default);') + return "\n".join(out) + + out = [] + out.append(f' TGeoTessellated *solid_{safe} = new TGeoTessellated("{shape_name}", {ntriangles});') + out.append(f' LoadFacets("{facet_abspath}", solid_{safe}, check);') + out.append(f' TGeoVolume *vol_{safe} = new TGeoVolume("{shape_name}", solid_{safe}, med_Default);') + return "\n".join(out) + + +def emit_assembly_cpp(lid: str, asm_display_name: str) -> str: + safe = sanitize_cpp_name(lid) + name = asm_display_name if asm_display_name else lid + return f' TGeoVolumeAssembly *asm_{safe} = new TGeoVolumeAssembly("{name}");' + + +# ------------------------------- +# Definition graph extraction +# ------------------------------- + +logical_volumes = {} # def_lid -> triangles +def_names = {} # def_lid -> human display name (may be "") +assemblies = set() # def_lid +placements = [] # (parent_def_lid, child_def_lid, gp_Trsf local) +top_defs = set() # top definition lids +visited_defs = set() # expanded defs + + +def cpp_var_for_def(lid: str) -> str: + safe = sanitize_cpp_name(lid) + return f"asm_{safe}" if lid in assemblies else f"vol_{safe}" + + +def expand_definition(def_label: TDF_Label, shape_tool, meshparam=None, scale_to_cm: float = 1.0): + def_lid = label_id(def_label) + if def_lid in visited_defs: + return + visited_defs.add(def_lid) + + nm = label_name(def_label) + if nm and def_lid not in def_names: + def_names[def_lid] = nm + elif def_lid not in def_names: + def_names[def_lid] = "" + + children = TDF_LabelSequence() + shape_tool.GetComponents(def_label, children) + has_children = children.Length() > 0 + + if has_children or shape_tool.IsAssembly(def_label): + assemblies.add(def_lid) + + for i in range(children.Length()): + child = children.Value(i + 1) + if shape_tool.IsReference(child): + referred = TDF_Label() + shape_tool.GetReferredShape(child, referred) + child_def_lid = label_id(referred) + + loc = shape_tool.GetLocation(child) + trsf = loc.Transformation() + placements.append((def_lid, child_def_lid, trsf)) + + expand_definition(referred, shape_tool, meshparam=meshparam, scale_to_cm=scale_to_cm) + else: + child_def_lid = label_id(child) + placements.append((def_lid, child_def_lid, gp_Trsf())) + expand_definition(child, shape_tool, meshparam=meshparam, scale_to_cm=scale_to_cm) + return + + if shape_tool.IsSimpleShape(def_label): + if def_lid not in logical_volumes: + shape = shape_tool.GetShape(def_label) + do_meshing = (meshparam is not None) and meshparam.get("do_meshing", None) is True + logical_volumes[def_lid] = triangulate_CAD_solid(shape, meshparam=meshparam, scale_to_cm=scale_to_cm) if do_meshing else triangulate_asbbox(shape, scale_to_cm=scale_to_cm) + return + + assemblies.add(def_lid) + + +def extract_graph(step_path: str, meshparam=None, scale_to_cm: float = 1.0): + global logical_volumes, def_names, assemblies, placements, top_defs, visited_defs + logical_volumes = {} + def_names = {} + assemblies = set() + placements = [] + top_defs = set() + visited_defs = set() + + doc, shape_tool = load_step_with_xcaf(step_path) + + roots = TDF_LabelSequence() + shape_tool.GetFreeShapes(roots) + + for i in range(roots.Length()): + root = roots.Value(i + 1) + if shape_tool.IsReference(root): + ref = TDF_Label() + shape_tool.GetReferredShape(root, ref) + top_defs.add(label_id(ref)) + expand_definition(ref, shape_tool, meshparam=meshparam, scale_to_cm=scale_to_cm) + else: + top_defs.add(label_id(root)) + expand_definition(root, shape_tool, meshparam=meshparam, scale_to_cm=scale_to_cm) + + return doc, shape_tool + + +# ------------------------------- +# ROOT macro emission +# ------------------------------- + +def emit_placement_cpp(parent_def: str, child_def: str, trsf: gp_Trsf, copy_no: int, scale_to_cm: float) -> str: + parent_cpp = cpp_var_for_def(parent_def) + child_cpp = cpp_var_for_def(child_def) + tr_name = f"tr_{sanitize_cpp_name(parent_def)}_{sanitize_cpp_name(child_def)}_{copy_no}" + return trsf_to_tgeo(trsf, tr_name, scale_to_cm) + f" {parent_cpp}->AddNode({child_cpp}, {copy_no}, {tr_name});\n" + + +def emit_root_macro(step_path: str, out_folder: _Path, meshparam=None, step_unit: str = "auto"): + if (step_unit or "auto").lower() == "auto": + detected = detect_step_length_unit(step_path) + scale_to_cm = step_unit_scale_to_cm(detected) + print(f"Detected STEP length unit: {detected} (scale to cm = {scale_to_cm})") + else: + scale_to_cm = step_unit_scale_to_cm(step_unit) + print(f"Using overridden STEP length unit: {step_unit} (scale to cm = {scale_to_cm})") + + extract_graph(step_path, meshparam=meshparam, scale_to_cm=scale_to_cm) + + out_folder = out_folder.expanduser().resolve() + out_folder.mkdir(parents=True, exist_ok=True) + + facet_files = {} # def_lid -> absolute path string + for lid, tris in logical_volumes.items(): + disp = def_names.get(lid, "") + volname = sanitize_filename(disp) if disp else "vol" + lidname = sanitize_filename(lid) + fname = f"facets_{volname}_{lidname}.bin" + fpath = (out_folder / fname).resolve() + write_facets_bin(fpath, tris) + facet_files[lid] = str(fpath).replace("\\", "\\\\") # C++ string literal safety + + cpp = [] + cpp.append(emit_cpp_prelude()) + + cpp.append("TGeoVolume* build(bool check=true) {") + cpp.append(' if (!gGeoManager) { throw std::runtime_error("gGeoManager is null. Call build_and_export() or create a TGeoManager first."); }') + cpp.append(emit_materials_cpp()) + + for lid in logical_volumes.keys(): + ntriangles = len(logical_volumes[lid]) + cpp.append(emit_tessellated_cpp(lid, def_names.get(lid, ""), facet_files[lid], ntriangles)) + + for lid in sorted(assemblies): + cpp.append(emit_assembly_cpp(lid, def_names.get(lid, ""))) + + for idx, (parent, child, trsf) in enumerate(placements, start=1): + cpp.append(emit_placement_cpp(parent, child, trsf, idx, scale_to_cm)) + + if len(top_defs) == 1: + top = next(iter(top_defs)) + cpp.append(f" return {cpp_var_for_def(top)};") + else: + cpp.append(' TGeoVolumeAssembly *asm_WORLD = new TGeoVolumeAssembly("WORLD");') + for i, node in enumerate(sorted(top_defs), start=1): + cpp.append(f" asm_WORLD->AddNode({cpp_var_for_def(node)}, {i});") + cpp.append(" return asm_WORLD;") + + cpp.append("}") + + # exports a function allowing to export the geometry to TGeo file + cpp.append('void build_and_export(const char* out_root = "geom.root", bool check=true) {') + cpp.append(' if (!gGeoManager) { new TGeoManager("geom","geom"); }') + cpp.append(' TGeoVolume* top = build(check);') + cpp.append(' gGeoManager->SetTopVolume(top);') + cpp.append(' gGeoManager->CloseGeometry();') + cpp.append(' gGeoManager->CheckOverlaps();') + cpp.append(' gGeoManager->Export(out_root);') + cpp.append('}') + + # exports a function to get get hold of the builder function in ALICE O2 + cpp.append('std::function get_builder_hook_checked() {') + cpp.append(' return []() { return build(true); };') + cpp.append('}') + # exports a function to get get hold of the builder function in ALICE O2 + cpp.append('std::function get_builder_hook_unchecked() {') + cpp.append(' return []() { return build(false); };') + cpp.append('}') + + return "\n".join(cpp) + + +# ------------------------------- +# Geometry Tree printing (debug) +# ------------------------------- + +def label_entry(label): + s = TCollection_AsciiString() + TDF_Tool.Entry(label, s) + return s.ToCString() + + +def traverse_print(label, shape_tool, depth=0): + indent = " " * depth + name = label.GetLabelName() + entry = label_entry(label) + print(f"{indent}- {name} =>[{entry}]") + + if shape_tool.IsReference(label): + ref_label = TDF_Label() + shape_tool.GetReferredShape(label, ref_label) + traverse_print(ref_label, shape_tool, depth + 1) + return + + children = TDF_LabelSequence() + shape_tool.GetComponents(label, children) + if children.Length() > 0 or shape_tool.IsAssembly(label): + for i in range(children.Length()): + traverse_print(children.Value(i + 1), shape_tool, depth + 1) + return + + if shape_tool.IsSimpleShape(label): + shape = shape_tool.GetShape(label) + print(f"{indent} [LogicalShape id={id(shape)}]") + + +def print_geom(step_file): + print(f"Printing GEOM hierarchy for {step_file}") + doc, shape_tool = load_step_with_xcaf(step_file) + roots = TDF_LabelSequence() + shape_tool.GetFreeShapes(roots) + for i in range(roots.Length()): + traverse_print(roots.Value(i + 1), shape_tool) + + +# ------------------------------- +# CLI +# ------------------------------- + +def main(): + ap = argparse.ArgumentParser(description="Convert STEP/XCAF to ROOT TGeo macro, facets in per-volume binary files.") + ap.add_argument("step", help="Input STEP file") + ap.add_argument("-o", "--out", default="geom.C", help="Output ROOT macro file name (default: geom.C)") + ap.add_argument("--output-folder", default="./", help="Output folder for macro + facet files") + ap.add_argument("--out-path", default=None, help="(deprecated) Alias for --output-folder") + ap.add_argument("--mesh", action="store_true", help="Use full BRepMesh triangulation instead of bounding boxes") + ap.add_argument("--print-tree", action="store_true", help="Just prints the geometry tree") + ap.add_argument("--mesh-prec", default=0.1, help="meshing precision. lower --> slower") + ap.add_argument("--step-unit", default="auto", choices=["auto", "mm", "cm", "m", "in", "ft"], help="STEP length unit override (default: auto-detect)") + + args = ap.parse_args() + + step_path = str(_Path(args.step).expanduser().resolve()) + if args.print_tree: + print_geom(step_path) + return + + out_folder = _Path(args.output_folder) + if args.out_path is not None: + out_folder = _Path(args.out_path) + + meshparam = {"do_meshing": args.mesh, "lin_defl": args.mesh_prec, "ang_defl": args.mesh_prec} + + out_folder = out_folder.expanduser().resolve() + out_folder.mkdir(parents=True, exist_ok=True) + + out_macro = (out_folder / _Path(args.out).name).resolve() + code = emit_root_macro(step_path, out_folder, meshparam=meshparam, step_unit=args.step_unit) + out_macro.write_text(code) + + print(f"Wrote ROOT macro: {out_macro}") + print(f"Wrote facet files into: {out_folder}") + print("In ROOT you can do:") + print(f" root -l {out_macro}") + print(' build_and_export("geom.root");') + + +if __name__ == "__main__": + main() diff --git a/scripts/geometry/README.md b/scripts/geometry/README.md new file mode 100644 index 0000000000000..4fb2d1ec610d4 --- /dev/null +++ b/scripts/geometry/README.md @@ -0,0 +1,27 @@ +This is the tool O2_CADtoTGeo.py which translates from geometries in STEP format (CAD export) to +TGeo. + +To use the tool, setup a conda environment with python-occ core installed. +The following should work on standard linux x86: + +``` +# -) download miniconda into $HOME/miniconda (if not already done) +if [ ! -d $HOME/miniconda ]; then + curl -fsSL https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-aarch64.sh -o miniconda.sh + bash miniconda.sh -b -p $HOME/miniconda +fi + +# -) source conda into the environment (in every shell you want to use this) +source $HOME/miniconda/etc/profile.d/conda.sh + +# -) Create an OCC environment (for OpenCacade) +conda create -n occ python=3.10 -y +conda activate occ + +# 3) Install OpenCascade Python bindings +conda install -c conda-forge pythonocc-core -y + +# 4) Run the tool, e.g. +conda activate occ +python PATH_TO_ALICEO2_SOURCES/scripts/geometry/O2_CADtoTGeo.py --help +``` \ No newline at end of file diff --git a/scripts/geometry/simulating_CAD_modules.md b/scripts/geometry/simulating_CAD_modules.md new file mode 100644 index 0000000000000..ccd59a3523781 --- /dev/null +++ b/scripts/geometry/simulating_CAD_modules.md @@ -0,0 +1,72 @@ +# ALICE-O2 GEANT Simulation of CAD Geometries + +These are a few notes related to the inclusion of external (CAD-described) detector modules into the O2 simulation framework. + +## Description of the Workflow + +In principle, such integration is now possible and requires the following steps: + +1. The CAD geometry needs to be exported to STEP format and must contain only the final geometry (no artificial eta-cut elements). Ideally, the geometry should be fully hierarchical with proper solid reuse. The solids should retain their proper surface representation for detailed analysis. + +2. A tool `O2-CADtoTGeo.py` is provided to convert the STEP geometry into TGeo format. The tool is part of AliceO2 and is based on Python bindings (OCC) for OpenCascade. The tool can be used as follows: + + ```bash + python O2-CADtoTGeo.py STEP_FILE --output-folder my_detector -o geom.C --mesh \ + --mesh-prec 0.2 + ``` + + This will create a ROOT macro file `geom.C` containing the geometry description in ROOT format, as well as several binary files describing the TGeo solids. The `geom.C` file can either be used directly in ROOT to inspect the geometry or be provided to ALICE-O2 for inclusion in the geometry. + +3. Introduction of materials/media in the file `geom.C`. Currently, the file `geom.C` needs to be patched or edited to properly include `TGeoMaterial`/`TGeoMedium` definitions and connect them to the relevant `TGeoVolume` objects. At present, every solid has the same dummy material attached, which is not realistic. It may be a good idea to create a new file `geom_withMaterials.C`, which differs from `geom.C` by the addition of these material definitions. + +4. Once the conversion is complete, the module can be inserted into the O2 geometry via the `ExternalModule` class. To do so, follow this pattern in `build_geometry.C`: + + ```cpp + if (isActivated("EXT")) { + o2::passive::ExternalModuleOptions options; + options.root_macro_file = "PATH_TO_MY_DETECTOR/my_detector/geom_withMaterials.C"; + options.anchor_volume = "barrel"; // hook this into barrel + auto rot = new TGeoCombiTrans(); + rot->RotateX(90); + rot->SetDy(30); // compensate for a shift of the barrel with respect to zero + options.placement = rot; + run->AddModule(new o2::passive::ExternalModule("A3VTX", "ALICE3 beam pipe", options)); + } + ``` + +5. Create a custom detector geometry list file `my_det.json` in JSON format that includes the external detector (and any other required components, such as the L3 magnet in this example): + + ```json + { + "MY_DET": [ + "EXT", + "MAG" + ] + } + ``` + +6. Run the Geant simulation with: + + ```bash + o2-sim --detectorList MY_DET:my_det.json -g pythia8pp .... + ``` + +## Known Limitations + +- The `O2-CADtoTGeo.py` tool currently converts geometries only into TGeoTessellated solids. This may be suboptimal for primitive shapes or only an approximation for shapes with exact second-order surfaces (e.g., tubes). The precision (and therefore the number of surface triangles) can be controlled with the `--mesh-prec` parameter. The smaller the value, the more precise the mesh. + +- Meshed solids created by the tool may have issues, such as topological errors or non-watertight surfaces. It is planned to include "healing" steps via additional processing with well-known geometry kernels (e.g., CGAL). + +- The tool does not currently export materials or TGeoMedia. These must be inserted or edited manually. It is planned to make this process more automatic and user-friendly. + +- The Python tool requires the OCC Python module, which is currently not part of our software distribution. We have found it most practical to run the tool in a separate conda environment (fully decoupled from the ALICE software stack). + +- The tool currently generates a `geom.C` macro file. In the future, it may be possible to directly create an in-memory TGeo representation for deeper integration. + +- Currently, only passive modules can be integrated. Treatment of sensitive volumes or parts will be addressed in a future step. + +## Software Installation + +- The simulation must be run in the standard O2 environment built with alibuild. + +- The CAD conversion tool must currently be run in a dedicated conda environment, as described in scripts/geometry/README.md in the AliceO2 source code. \ No newline at end of file From 17d865e646a90d7e19ae43424d2404dd163885ec Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Fri, 13 Feb 2026 16:34:50 +0100 Subject: [PATCH 202/234] Fix Header info forwarding --- Generators/src/GeneratorHybrid.cxx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Generators/src/GeneratorHybrid.cxx b/Generators/src/GeneratorHybrid.cxx index 2a13f9876e717..f853b772e3cd3 100644 --- a/Generators/src/GeneratorHybrid.cxx +++ b/Generators/src/GeneratorHybrid.cxx @@ -420,6 +420,7 @@ bool GeneratorHybrid::importParticles() mMCEventHeader.clearInfo(); if (mCocktailMode) { // in cocktail mode we need to merge the particles from the different generators + bool baseGen = true; // first generator of the cocktail is used as reference to update the event header information for (auto subIndex : subGenIndex) { LOG(info) << "Importing particles for task " << subIndex; auto subParticles = gens[subIndex]->getParticles(); @@ -441,8 +442,10 @@ bool GeneratorHybrid::importParticles() } mParticles.insert(mParticles.end(), subParticles.begin(), subParticles.end()); - // fetch the event Header information from the underlying generator - gens[subIndex]->updateHeader(&mMCEventHeader); + if (baseGen) { + gens[subIndex]->updateHeader(&mMCEventHeader); + baseGen = false; + } mInputTaskQueue.push(subIndex); mTasksStarted++; } @@ -481,7 +484,9 @@ bool GeneratorHybrid::importParticles() void GeneratorHybrid::updateHeader(o2::dataformats::MCEventHeader* eventHeader) { if (eventHeader) { - // we forward the original header information if any + // Forward the base class fields from FairMCEventHeader + static_cast(*eventHeader) = static_cast(mMCEventHeader); + // Copy the key-value store info eventHeader->copyInfoFrom(mMCEventHeader); // put additional information about From 8361c429fd87b9d0cb215b1ac83f5ee1fd162269 Mon Sep 17 00:00:00 2001 From: ddobrigk Date: Sat, 14 Feb 2026 09:47:17 +0100 Subject: [PATCH 203/234] Add option to compress out non-dEdx info in TrackQA table (#15045) * Add compress-out option for non-dEdx info in TrackQA * Add compress-out option for non-dEdx info in TrackQA * Retain also TPC-only tracks used by svtx, strangeness tracking * Please consider the following formatting changes --------- Co-authored-by: ALICE Action Bot --- .../AODProducerWorkflowSpec.h | 1 + Detectors/AOD/src/AODProducerWorkflowSpec.cxx | 34 ++++++++++--------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h b/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h index 2d16f343dc1eb..2c58db42ed856 100644 --- a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h +++ b/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h @@ -238,6 +238,7 @@ class AODProducerWorkflowDPL : public Task bool mPropTracks{false}; bool mPropMuons{false}; float mTrackQCKeepGlobalTracks{false}; + float mTrackQCRetainOnlydEdx{false}; float mTrackQCFraction{0.00}; int64_t mTrackQCNTrCut{4}; float mTrackQCDCAxy{3.}; diff --git a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx index be169ad4be19d..852419a9895eb 100644 --- a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx +++ b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx @@ -363,10 +363,10 @@ void AODProducerWorkflowDPL::addToTracksQATable(TracksQACursorType& tracksQACurs { tracksQACursor( trackQAInfoHolder.trackID, - truncateFloatFraction(trackQAInfoHolder.tpcTime0, mTPCTime0), + mTrackQCRetainOnlydEdx ? 0.0f : truncateFloatFraction(trackQAInfoHolder.tpcTime0, mTPCTime0), truncateFloatFraction(trackQAInfoHolder.tpcdEdxNorm, mTrackSignal), - trackQAInfoHolder.tpcdcaR, - trackQAInfoHolder.tpcdcaZ, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.tpcdcaR, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.tpcdcaZ, trackQAInfoHolder.tpcClusterByteMask, trackQAInfoHolder.tpcdEdxMax0R, trackQAInfoHolder.tpcdEdxMax1R, @@ -376,18 +376,18 @@ void AODProducerWorkflowDPL::addToTracksQATable(TracksQACursorType& tracksQACurs trackQAInfoHolder.tpcdEdxTot1R, trackQAInfoHolder.tpcdEdxTot2R, trackQAInfoHolder.tpcdEdxTot3R, - trackQAInfoHolder.dRefContY, - trackQAInfoHolder.dRefContZ, - trackQAInfoHolder.dRefContSnp, - trackQAInfoHolder.dRefContTgl, - trackQAInfoHolder.dRefContQ2Pt, - trackQAInfoHolder.dRefGloY, - trackQAInfoHolder.dRefGloZ, - trackQAInfoHolder.dRefGloSnp, - trackQAInfoHolder.dRefGloTgl, - trackQAInfoHolder.dRefGloQ2Pt, - trackQAInfoHolder.dTofdX, - trackQAInfoHolder.dTofdZ); + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefContY, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefContZ, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefContSnp, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefContTgl, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefContQ2Pt, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefGloY, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefGloZ, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefGloSnp, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefGloTgl, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dRefGloQ2Pt, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dTofdX, + mTrackQCRetainOnlydEdx ? std::numeric_limits::min() : trackQAInfoHolder.dTofdZ); } template @@ -499,7 +499,7 @@ void AODProducerWorkflowDPL::fillTrackTablesPerCollision(int collisionID, float weight = 0; static std::uniform_real_distribution<> distr(0., 1.); - bool writeQAData = o2::math_utils::Tsallis::downsampleTsallisCharged(data.getTrackParam(trackIndex).getPt(), mTrackQCFraction, mSqrtS, weight, distr(mGenerator)) || (src != GIndex::TPC && mTrackQCKeepGlobalTracks); + bool writeQAData = o2::math_utils::Tsallis::downsampleTsallisCharged(data.getTrackParam(trackIndex).getPt(), mTrackQCFraction, mSqrtS, weight, distr(mGenerator)) || ((src != GIndex::TPC || mGIDUsedBySVtx.find(trackIndex) != mGIDUsedBySVtx.end() || mGIDUsedByStr.find(trackIndex) != mGIDUsedByStr.end()) && mTrackQCKeepGlobalTracks); auto extraInfoHolder = processBarrelTrack(collisionID, collisionBC, trackIndex, data, bcsMap); if (writeQAData) { @@ -1720,6 +1720,7 @@ void AODProducerWorkflowDPL::init(InitContext& ic) } } mTrackQCKeepGlobalTracks = ic.options().get("trackqc-keepglobaltracks"); + mTrackQCRetainOnlydEdx = ic.options().get("trackqc-retainonlydedx"); mTrackQCFraction = ic.options().get("trackqc-fraction"); mTrackQCNTrCut = ic.options().get("trackqc-NTrCut"); mTrackQCDCAxy = ic.options().get("trackqc-tpc-dca"); @@ -3356,6 +3357,7 @@ DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, boo ConfigParamSpec{"propagate-muons", VariantType::Bool, false, {"Propagate muons to IP"}}, ConfigParamSpec{"thin-tracks", VariantType::Bool, false, {"Produce thinned track tables"}}, ConfigParamSpec{"trackqc-keepglobaltracks", VariantType::Bool, false, {"Always keep TrackQA for global tracks"}}, + ConfigParamSpec{"trackqc-retainonlydedx", VariantType::Bool, false, {"Keep only dEdx information, zero out everything else"}}, ConfigParamSpec{"trackqc-fraction", VariantType::Float, float(0.1), {"Fraction of tracks to QC"}}, ConfigParamSpec{"trackqc-NTrCut", VariantType::Int64, 4L, {"Minimal length of the track - in amount of tracklets"}}, ConfigParamSpec{"trackqc-tpc-dca", VariantType::Float, 3.f, {"Keep TPC standalone track with this DCAxy to the PV"}}, From b87ed891b1f785c042f7cc9f2d490d3f5a6dd3f1 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Sun, 15 Feb 2026 14:29:48 +0100 Subject: [PATCH 204/234] DPL Examples: use the new completion policy for parallel processing (#15059) This demonstrates how the new policy can be used in conjunction with wildcards in order to simplify parallelism based on the subSpecification. --- .../Framework/CompletionPolicyHelpers.h | 1 - .../TestWorkflows/src/o2ParallelWorkflow.cxx | 77 ++++++++++++------- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/Framework/Core/include/Framework/CompletionPolicyHelpers.h b/Framework/Core/include/Framework/CompletionPolicyHelpers.h index 9fce626854e5b..09ea8b7ea6b61 100644 --- a/Framework/Core/include/Framework/CompletionPolicyHelpers.h +++ b/Framework/Core/include/Framework/CompletionPolicyHelpers.h @@ -11,7 +11,6 @@ #ifndef O2_FRAMEWORK_COMPLETIONPOLICYHELPERS_H_ #define O2_FRAMEWORK_COMPLETIONPOLICYHELPERS_H_ -#include "Framework/ChannelSpec.h" #include "Framework/CompletionPolicy.h" #include "Headers/DataHeader.h" diff --git a/Framework/TestWorkflows/src/o2ParallelWorkflow.cxx b/Framework/TestWorkflows/src/o2ParallelWorkflow.cxx index 841f4a8f2b9bd..bdc08ad45ea24 100644 --- a/Framework/TestWorkflows/src/o2ParallelWorkflow.cxx +++ b/Framework/TestWorkflows/src/o2ParallelWorkflow.cxx @@ -9,7 +9,12 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include "Framework/ConcreteDataMatcher.h" #include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/InputRecordWalker.h" +#include "Framework/Logger.h" #include #include @@ -29,13 +34,16 @@ void customize(std::vector& workflowOptions) ConfigParamSpec{"3-layer-pipelining", VariantType::Int, 1, {timeHelp}}); } +void customize(std::vector& policies) +{ + policies = { + CompletionPolicyHelpers::consumeWhenPastOldestPossibleTimeframe("merger-policy", [](auto const&) -> bool { return true; })}; +} + #include "Framework/runDataProcessing.h" #include "Framework/DataProcessorSpec.h" #include "Framework/DataSpecUtils.h" #include "Framework/ParallelContext.h" -#include "Framework/ControlService.h" - -#include "Framework/Logger.h" #include @@ -43,22 +51,24 @@ using DataHeader = o2::header::DataHeader; DataProcessorSpec templateProcessor() { - return DataProcessorSpec{"some-processor", { - InputSpec{"x", "TST", "A", 0, Lifetime::Timeframe}, - }, - { + return DataProcessorSpec{.name = "some-processor", + .inputs = { + InputSpec{"x", "TST", "A", 0, Lifetime::Timeframe}, + }, + .outputs = { OutputSpec{"TST", "P", 0, Lifetime::Timeframe}, }, // The producer is stateful, we use a static for the state in this // particular case, but a Singleton or a captured new object would // work as well. - AlgorithmSpec{[](InitContext& setup) { + .algorithm = AlgorithmSpec{[](InitContext& setup) { srand(setup.services().get().index1D()); return [](ProcessingContext& ctx) { // Create a single output. size_t index = ctx.services().get().index1D(); - auto& aData = ctx.outputs().make( + auto& i = ctx.outputs().make( Output{"TST", "P", static_cast(index)}, 1); + i[0] = index; std::this_thread::sleep_for(std::chrono::seconds(rand() % 5)); }; }}}; @@ -86,34 +96,43 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) outputSpecs.emplace_back("TST", "A", ssi); } - workflow.push_back(DataProcessorSpec{"reader", {}, outputSpecs, AlgorithmSpec{[jobs](InitContext& initCtx) { - return [jobs](ProcessingContext& ctx) { - for (size_t ji = 0; ji < jobs; ++ji) { - ctx.outputs().make(Output{"TST", "A", static_cast(ji)}, - 1); - } - }; - }}}); + workflow.push_back(DataProcessorSpec{ + .name = "reader", + .outputs = outputSpecs, + .algorithm = AlgorithmSpec{[jobs](InitContext& initCtx) { + return [jobs](ProcessingContext& ctx) { + static int count = 0; + for (size_t ji = 0; ji < jobs; ++ji) { + int& i = ctx.outputs().make(Output{"TST", "A", static_cast(ji)}); + i = count * 100 + ji; + } + count++; + }; + }}}); workflow.push_back(timePipeline(DataProcessorSpec{ - "merger", - mergeInputs(InputSpec{"x", "TST", "P"}, - jobs, - [](InputSpec& input, size_t index) { - DataSpecUtils::updateMatchingSubspec(input, index); - }), - {OutputSpec{{"out"}, "TST", "M"}}, - AlgorithmSpec{[](InitContext& setup) { + .name = "merger", + .inputs = {InputSpec{"all", ConcreteDataTypeMatcher{"TST", "P"}}}, + .outputs = {OutputSpec{{"out"}, "TST", "M"}}, + .algorithm = AlgorithmSpec{[](InitContext& setup) { return [](ProcessingContext& ctx) { + LOGP(info, "Run"); + for (const auto& input : o2::framework::InputRecordWalker(ctx.inputs())) { + if (input.header == nullptr) { + LOGP(error, "Missing header"); + continue; + } + int record = *(int*)input.payload; + LOGP(info, "Record {}", record); + } ctx.outputs().make(OutputRef("out", 0), 1); }; }}}, stages)); workflow.push_back(DataProcessorSpec{ - "writer", - {InputSpec{"x", "TST", "M"}}, - {}, - AlgorithmSpec{[](InitContext& setup) { + .name = "writer", + .inputs = {InputSpec{"x", "TST", "M"}}, + .algorithm = AlgorithmSpec{[](InitContext& setup) { return [](ProcessingContext& ctx) { }; }}}); From cbace3965ebdcb915f78a5535d447571ae056a68 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Sun, 15 Feb 2026 21:48:06 +0100 Subject: [PATCH 205/234] GPU TPC: Assume more sector track hits for low field data --- GPU/GPUTracking/DataTypes/GPUMemorySizeScalers.h | 6 ++++-- GPU/GPUTracking/SectorTracker/GPUTPCTracker.cxx | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/GPU/GPUTracking/DataTypes/GPUMemorySizeScalers.h b/GPU/GPUTracking/DataTypes/GPUMemorySizeScalers.h index ff8abdc1a491e..067a11817d7ac 100644 --- a/GPU/GPUTracking/DataTypes/GPUMemorySizeScalers.h +++ b/GPU/GPUTracking/DataTypes/GPUMemorySizeScalers.h @@ -43,7 +43,9 @@ struct GPUMemorySizeScalers { double tpcClustersPerPeak = 0.9; double tpcStartHitsPerHit = 0.08; double tpcTrackletsPerStartHit = 0.8; + double tpcTrackletsPerStartHitLowField = 0.85; double tpcTrackletHitsPerHit = 5; + double tpcTrackletHitsPerHitLowField = 7; double tpcSectorTracksPerHit = 0.02; double tpcSectorTrackHitsPerHit = 0.8; double tpcSectorTrackHitsPerHitWithRejection = 1.0; @@ -80,8 +82,8 @@ struct GPUMemorySizeScalers { inline size_t NTPCClusters(size_t tpcDigits, bool perSector = false) { return getValue(perSector ? tpcMaxSectorClusters : tpcMaxClusters, (conservative ? 1.0 : tpcClustersPerPeak) * NTPCPeaks(tpcDigits, perSector)); } inline size_t NTPCStartHits(size_t tpcHits) { return getValue(tpcMaxStartHits, tpcHits * tpcStartHitsPerHit); } inline size_t NTPCRowStartHits(size_t tpcHits) { return getValue(tpcMaxRowStartHits, std::max(NTPCStartHits(tpcHits) * (tpcHits < 30000000 ? 20 : 12) / GPUCA_ROW_COUNT, tpcMinRowStartHits)); } - inline size_t NTPCTracklets(size_t tpcHits) { return getValue(tpcMaxTracklets, NTPCStartHits(tpcHits) * tpcTrackletsPerStartHit); } - inline size_t NTPCTrackletHits(size_t tpcHits) { return getValue(tpcMaxTrackletHits, hitOffset + tpcHits * tpcTrackletHitsPerHit); } + inline size_t NTPCTracklets(size_t tpcHits, bool lowField) { return getValue(tpcMaxTracklets, NTPCStartHits(tpcHits) * (lowField ? tpcTrackletsPerStartHitLowField : tpcTrackletsPerStartHit)); } + inline size_t NTPCTrackletHits(size_t tpcHits, bool lowField) { return getValue(tpcMaxTrackletHits, hitOffset + tpcHits * (lowField ? tpcTrackletHitsPerHitLowField : tpcTrackletHitsPerHit)); } inline size_t NTPCSectorTracks(size_t tpcHits) { return getValue(tpcMaxSectorTracks, tpcHits * tpcSectorTracksPerHit); } inline size_t NTPCSectorTrackHits(size_t tpcHits, uint8_t withRejection = 0) { return getValue(tpcMaxSectorTrackHits, tpcHits * (withRejection ? tpcSectorTrackHitsPerHitWithRejection : tpcSectorTrackHitsPerHit)); } inline size_t NTPCMergedTracks(size_t tpcSectorTracks) { return getValue(tpcMaxMergedTracks, tpcSectorTracks * (conservative ? 1.0 : tpcMergedTrackPerSectorTrack)); } diff --git a/GPU/GPUTracking/SectorTracker/GPUTPCTracker.cxx b/GPU/GPUTracking/SectorTracker/GPUTPCTracker.cxx index 03931f73a4a12..506f90c55abf3 100644 --- a/GPU/GPUTracking/SectorTracker/GPUTPCTracker.cxx +++ b/GPU/GPUTracking/SectorTracker/GPUTPCTracker.cxx @@ -144,8 +144,9 @@ void GPUTPCTracker::SetMaxData(const GPUTrackingInOutPointers& io) } else { mNMaxRowStartHits = mRec->MemoryScalers()->NTPCRowStartHits(mData.NumberOfHits()); } - mNMaxTracklets = mRec->MemoryScalers()->NTPCTracklets(mData.NumberOfHits()); - mNMaxRowHits = mRec->MemoryScalers()->NTPCTrackletHits(mData.NumberOfHits()); + bool lowField = CAMath::Abs(Param().bzkG) < 4; + mNMaxTracklets = mRec->MemoryScalers()->NTPCTracklets(mData.NumberOfHits(), lowField); + mNMaxRowHits = mRec->MemoryScalers()->NTPCTrackletHits(mData.NumberOfHits(), lowField); mNMaxTracks = mRec->MemoryScalers()->NTPCSectorTracks(mData.NumberOfHits()); if (io.clustersNative) { uint32_t sectorOffset = mISector >= GPUCA_NSECTORS / 2 ? GPUCA_NSECTORS / 2 : 0; From 23a36dfe2517df697788634b9a64088e86c0822b Mon Sep 17 00:00:00 2001 From: Marco Giacalone Date: Mon, 16 Feb 2026 14:10:23 +0100 Subject: [PATCH 206/234] Add Kine publisher test (#15058) --- prodtests/full_system_test.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/prodtests/full_system_test.sh b/prodtests/full_system_test.sh index 82021d6c65e63..07ccdf01d4566 100755 --- a/prodtests/full_system_test.sh +++ b/prodtests/full_system_test.sh @@ -168,6 +168,13 @@ taskwrapper collcontext.log o2-steer-colcontexttool \ SIMOPTKEY+="GenTPCLoopers.colsys=${BEAMTYPE};" taskwrapper sim.log o2-sim ${FST_BFIELD+--field=}${FST_BFIELD} --vertexMode kCollContext --seed $O2SIMSEED -n $NEvents --configKeyValues "\"$SIMOPTKEY\"" -g ${FST_GENERATOR} -e ${FST_MC_ENGINE} -j $NJOBS --run ${RUNNUMBER} -o o2sim --fromCollContext collisioncontext.root:o2sim +# Test MCTracks to AO2D conversion tool +taskwrapper kine2aod.log "o2-sim-kine-publisher -b --kineFileName o2sim --aggregate-timeframe $NEvents | o2-sim-mctracks-to-aod -b --aod-writer-keep dangling | o2-analysis-mctracks-to-aod-simple-task -b" +if [[ ! -s AnalysisResults_trees.root ]] || [[ ! -s AnalysisResults.root ]]; then + echo "Error: AnalysisResults_trees.root (AO2D from Kine file) or AnalysisResults.root (simple analysis task output) missing or empty" + exit 1 +fi + if [[ $DO_EMBEDDING == 1 ]]; then taskwrapper embed.log o2-sim ${FST_BFIELD+--field=}${FST_BFIELD} -j $NJOBS --run ${RUNNUMBER} -n $NEvents -g pythia8pp -e ${FST_MC_ENGINE} -o sig --configKeyValues ${FST_EMBEDDING_CONFIG} --embedIntoFile o2sim_MCHeader.root fi From 75a357d3e2fcb58cadca886055691d53eac62004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Piero=C5=BCak?= <94726725+wpierozak@users.noreply.github.com> Date: Mon, 16 Feb 2026 14:14:28 +0100 Subject: [PATCH 207/234] Afit 124 (#14985) * FV0: included dead channel map in reconstruction * FV0: fixed fetch of dead channel map in reco * FV0:Added debug log when data from dead channel is discard * FV0: changed handling of dead channel in reco * Implementation DeadChannelMap in FDD/FT0 * Updaed FDD reco * FIT:Fixed application of DeadChannelMap in FV0 and FDD reconstruction task * Fixed missing constructor arguments for FDD RecoSepc * Please consider the following formatting changes --------- Co-authored-by: wpierozak Co-authored-by: wpierozak Co-authored-by: ALICE Action Bot --- .../include/FDDReconstruction/Reconstructor.h | 9 ++++++- .../FDD/reconstruction/src/Reconstructor.cxx | 5 ++++ .../include/FDDWorkflow/RecoWorkflow.h | 2 +- .../include/FDDWorkflow/ReconstructorSpec.h | 10 +++++-- .../FIT/FDD/workflow/src/RecoWorkflow.cxx | 4 +-- .../FDD/workflow/src/ReconstructorSpec.cxx | 23 ++++++++++++++-- .../FDD/workflow/src/fdd-reco-workflow.cxx | 4 ++- .../FT0Reconstruction/CollisionTimeRecoTask.h | 7 +++++ .../src/CollisionTimeRecoTask.cxx | 4 +++ .../include/FT0Workflow/RecoWorkflow.h | 2 +- .../include/FT0Workflow/ReconstructionSpec.h | 6 +++-- .../FIT/FT0/workflow/src/RecoWorkflow.cxx | 4 +-- .../FT0/workflow/src/ReconstructionSpec.cxx | 22 +++++++++++++-- .../FT0/workflow/src/ft0-reco-workflow.cxx | 6 +++-- .../include/FV0Reconstruction/BaseRecoTask.h | 6 +++-- .../FV0/reconstruction/src/BaseRecoTask.cxx | 27 +++++++++++-------- .../include/FV0Workflow/RecoWorkflow.h | 2 +- .../include/FV0Workflow/ReconstructionSpec.h | 6 +++-- .../FIT/FV0/workflow/src/RecoWorkflow.cxx | 5 ++-- .../FV0/workflow/src/ReconstructionSpec.cxx | 21 ++++++++++----- .../FV0/workflow/src/fv0-reco-workflow.cxx | 4 ++- 21 files changed, 135 insertions(+), 44 deletions(-) diff --git a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/Reconstructor.h b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/Reconstructor.h index 161b800a2c3ca..8881605b652ac 100644 --- a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/Reconstructor.h +++ b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/Reconstructor.h @@ -17,6 +17,7 @@ #include #include "DataFormatsFDD/Digit.h" #include "DataFormatsFDD/RecPoint.h" +#include "DataFormatsFIT/DeadChannelMap.h" namespace o2 { namespace fdd @@ -30,10 +31,16 @@ class Reconstructor gsl::span inChData, std::vector& RecPoints, std::vector& outChData); - void finish(); + void setDeadChannelMap(o2::fit::DeadChannelMap const* deadChannelMap) + { + LOG(info) << "Updated dead channel map"; + mDeadChannelMap = deadChannelMap; + } + private: + o2::fit::DeadChannelMap const* mDeadChannelMap = nullptr; ClassDefNV(Reconstructor, 3); }; } // namespace fdd diff --git a/Detectors/FIT/FDD/reconstruction/src/Reconstructor.cxx b/Detectors/FIT/FDD/reconstruction/src/Reconstructor.cxx index 3a87a11046a77..7d133e30df08e 100644 --- a/Detectors/FIT/FDD/reconstruction/src/Reconstructor.cxx +++ b/Detectors/FIT/FDD/reconstruction/src/Reconstructor.cxx @@ -33,7 +33,12 @@ void Reconstructor::process(o2::fdd::Digit const& digitBC, gsl::spanisChannelAlive(inChData[ich].mPMNumber)) { + LOG(debug) << "Channel " << ich << " is dead - discarding data"; + continue; + } bool inTime = inChData[ich].getFlag(ChannelData::EEventDataBit::kIsEventInTVDC); bool inAdcGate = inChData[ich].getFlag(ChannelData::EEventDataBit::kIsCFDinADCgate); if (inAdcGate) { diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecoWorkflow.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecoWorkflow.h index 2dbd854e34eee..0d5d308216bb0 100644 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecoWorkflow.h +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecoWorkflow.h @@ -20,7 +20,7 @@ namespace o2 { namespace fdd { -framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut); +framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut, bool useDeadChannelMap); } // namespace fdd } // namespace o2 #endif diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/ReconstructorSpec.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/ReconstructorSpec.h index 7dcb5d9aaba40..8f20ff1513ab4 100644 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/ReconstructorSpec.h +++ b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/ReconstructorSpec.h @@ -18,6 +18,8 @@ #include "Framework/Task.h" #include "FDDReconstruction/Reconstructor.h" #include "DataFormatsFDD/RecPoint.h" +#include "DataFormatsFIT/DeadChannelMap.h" +#include "Framework/ConcreteDataMatcher.h" using namespace o2::framework; @@ -29,21 +31,25 @@ namespace fdd class FDDReconstructorDPL : public Task { public: - FDDReconstructorDPL(bool useMC) : mUseMC(useMC) {} + FDDReconstructorDPL(bool useMC, bool useDeadChannelMap) : mUseMC(useMC), mUseDeadChannelMap(useDeadChannelMap) {} ~FDDReconstructorDPL() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; + void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final; private: bool mUseMC = true; + bool mUseDeadChannelMap = true; + bool mUpdateDeadChannelMap = true; std::vector mRecPoints; std::vector mRecChData; + o2::fit::DeadChannelMap const* mDeadChannelMap; o2::fdd::Reconstructor mReco; o2::header::DataOrigin mOrigin = o2::header::gDataOriginFDD; }; /// create a processor spec -framework::DataProcessorSpec getFDDReconstructorSpec(bool useMC = true); +framework::DataProcessorSpec getFDDReconstructorSpec(bool useMC = true, bool useDeadChannelMap = true); } // namespace fdd } // namespace o2 diff --git a/Detectors/FIT/FDD/workflow/src/RecoWorkflow.cxx b/Detectors/FIT/FDD/workflow/src/RecoWorkflow.cxx index a7d4c15af81bb..b464e689f7a75 100644 --- a/Detectors/FIT/FDD/workflow/src/RecoWorkflow.cxx +++ b/Detectors/FIT/FDD/workflow/src/RecoWorkflow.cxx @@ -22,14 +22,14 @@ namespace o2 namespace fdd { -framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut) +framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut, bool useDeadChannelMap) { framework::WorkflowSpec specs; if (!disableRootInp) { specs.emplace_back(o2::fdd::getFDDDigitReaderSpec(useMC)); } - specs.emplace_back(o2::fdd::getFDDReconstructorSpec(useMC)); + specs.emplace_back(o2::fdd::getFDDReconstructorSpec(useMC, useDeadChannelMap)); if (!disableRootOut) { specs.emplace_back(o2::fdd::getFDDRecPointWriterSpec(useMC)); } diff --git a/Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx b/Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx index b7a0b9876a2ee..1d5d599b5ee31 100644 --- a/Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx +++ b/Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx @@ -18,6 +18,7 @@ #include "FDDWorkflow/ReconstructorSpec.h" #include "DataFormatsFDD/Digit.h" #include "DataFormatsFDD/MCLabel.h" +#include "Framework/CCDBParamSpec.h" using namespace o2::framework; @@ -44,6 +45,11 @@ void FDDReconstructorDPL::run(ProcessingContext& pc) // lblPtr = labels.get(); LOG(info) << "Ignoring MC info"; } + if (mUseDeadChannelMap && mUpdateDeadChannelMap) { + LOG(info) << "Populating reconsturctor object with Dead Channel Map object"; + auto deadChannelMap = pc.inputs().get("deadChannelMap"); + mReco.setDeadChannelMap(deadChannelMap.get()); + } int nDig = digitsBC.size(); mRecPoints.reserve(nDig); mRecChData.reserve(digitsCh.size()); @@ -58,16 +64,29 @@ void FDDReconstructorDPL::run(ProcessingContext& pc) pc.outputs().snapshot(Output{mOrigin, "RECCHDATA", 0}, mRecChData); } -DataProcessorSpec getFDDReconstructorSpec(bool useMC) +void FDDReconstructorDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) +{ + if (matcher == ConcreteDataMatcher("FDD", "DeadChannelMap", 0)) { + mUpdateDeadChannelMap = false; + return; + } +} + +DataProcessorSpec getFDDReconstructorSpec(bool useMC, bool useDeadChannelMap) { std::vector inputSpec; std::vector outputSpec; inputSpec.emplace_back("digitsBC", o2::header::gDataOriginFDD, "DIGITSBC", 0, Lifetime::Timeframe); inputSpec.emplace_back("digitsCh", o2::header::gDataOriginFDD, "DIGITSCH", 0, Lifetime::Timeframe); + if (useMC) { LOG(info) << "Currently FDDReconstructor does not consume and provide MC truth"; // inputSpec.emplace_back("labels", o2::header::gDataOriginFDD, "DIGITSMCTR", 0, Lifetime::Timeframe); } + if (useDeadChannelMap) { + LOG(info) << "Dead channel map will be applied during reconstruction"; + inputSpec.emplace_back("deadChannelMap", o2::header::gDataOriginFDD, "DeadChannelMap", 0, Lifetime::Condition, ccdbParamSpec("FDD/Calib/DeadChannelMap")); + } outputSpec.emplace_back(o2::header::gDataOriginFDD, "RECPOINTS", 0, Lifetime::Timeframe); outputSpec.emplace_back(o2::header::gDataOriginFDD, "RECCHDATA", 0, Lifetime::Timeframe); @@ -75,7 +94,7 @@ DataProcessorSpec getFDDReconstructorSpec(bool useMC) "fdd-reconstructor", inputSpec, outputSpec, - AlgorithmSpec{adaptFromTask(useMC)}, + AlgorithmSpec{adaptFromTask(useMC, useDeadChannelMap)}, Options{}}; } diff --git a/Detectors/FIT/FDD/workflow/src/fdd-reco-workflow.cxx b/Detectors/FIT/FDD/workflow/src/fdd-reco-workflow.cxx index 652ddb8bd2a29..888792425909b 100644 --- a/Detectors/FIT/FDD/workflow/src/fdd-reco-workflow.cxx +++ b/Detectors/FIT/FDD/workflow/src/fdd-reco-workflow.cxx @@ -38,6 +38,7 @@ void customize(std::vector& workflowOptions) {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}, {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input readers"}}, {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}, + {"disable-dead-channel-map", o2::framework::VariantType::Bool, false, {"disable dead channel map"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); @@ -57,8 +58,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto useMC = !configcontext.options().get("disable-mc"); auto disableRootInp = configcontext.options().get("disable-root-input"); auto disableRootOut = configcontext.options().get("disable-root-output"); + bool useDeadChannelMap = !configcontext.options().get("disable-dead-channel-map"); - auto wf = o2::fdd::getRecoWorkflow(useMC, disableRootInp, disableRootOut); + auto wf = o2::fdd::getRecoWorkflow(useMC, disableRootInp, disableRootOut, useDeadChannelMap); // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit o2::raw::HBFUtilsInitializer hbfIni(configcontext, wf); diff --git a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CollisionTimeRecoTask.h b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CollisionTimeRecoTask.h index ff3f8384f488d..9f6cd500b9e74 100644 --- a/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CollisionTimeRecoTask.h +++ b/Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CollisionTimeRecoTask.h @@ -21,6 +21,7 @@ #include "DataFormatsFT0/FT0ChannelTimeCalibrationObject.h" #include "DataFormatsFT0/SpectraInfoObject.h" #include "DataFormatsFT0/SlewingCoef.h" +#include "DataFormatsFIT/DeadChannelMap.h" #include #include #include @@ -57,10 +58,16 @@ class CollisionTimeRecoTask LOG(info) << "Init for slewing calib object"; mCalibSlew = calibSlew->makeSlewingPlots(); }; + void SetDeadChannelMap(const o2::fit::DeadChannelMap* deadChannelMap) + { + LOG(info) << "Updated dead channel map for CollisionTimeRecoTask"; + mDeadChannelMap = deadChannelMap; + } float getTimeInPS(const o2::ft0::ChannelData& channelData); private: o2::ft0::TimeSpectraInfoObject const* mTimeCalibObject = nullptr; + const o2::fit::DeadChannelMap* mDeadChannelMap = nullptr; typename o2::ft0::SlewingCoef::SlewingPlots_t mCalibSlew{}; }; } // namespace ft0 diff --git a/Detectors/FIT/FT0/reconstruction/src/CollisionTimeRecoTask.cxx b/Detectors/FIT/FT0/reconstruction/src/CollisionTimeRecoTask.cxx index 7363cef57cf31..3e3ffe52671e9 100644 --- a/Detectors/FIT/FT0/reconstruction/src/CollisionTimeRecoTask.cxx +++ b/Detectors/FIT/FT0/reconstruction/src/CollisionTimeRecoTask.cxx @@ -67,6 +67,10 @@ RP CollisionTimeRecoTask::processDigit(const o2::ft0::Digit& digit, // Reference channels shouldn't participate in reco at all! continue; } + if (mDeadChannelMap && !mDeadChannelMap->isChannelAlive(channelData.ChId)) { + LOG(debug) << "Channel " << channelData.ChId << " is dead - discarding data"; + continue; + } const float timeInPS = getTimeInPS(channelData); if (ChannelFilterParam::Instance().checkAll(channelData)) { outChData.emplace_back(channelData.ChId, timeInPS, (float)channelData.QTCAmpl, channelData.ChainQTC); diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecoWorkflow.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecoWorkflow.h index 3c6e4599a250c..6de23a1c66bfd 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecoWorkflow.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/RecoWorkflow.h @@ -20,7 +20,7 @@ namespace o2 { namespace ft0 { -framework::WorkflowSpec getRecoWorkflow(bool useMC, std::string ccdbpath, bool useTimeOffsetCalib, bool useSlewingCalib, bool disableRootInp, bool disableRootOut); +framework::WorkflowSpec getRecoWorkflow(bool useMC, std::string ccdbpath, bool useTimeOffsetCalib, bool useSlewingCalib, bool disableRootInp, bool disableRootOut, bool useDeadChannelMap = true); } // namespace ft0 } // namespace o2 #endif diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/ReconstructionSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/ReconstructionSpec.h index 1c671352e6ba7..307b2109fe35f 100644 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/ReconstructionSpec.h +++ b/Detectors/FIT/FT0/workflow/include/FT0Workflow/ReconstructionSpec.h @@ -34,7 +34,7 @@ class ReconstructionDPL : public Task static constexpr int NCHANNELS = o2::ft0::Geometry::Nchannels; public: - ReconstructionDPL(bool useMC, const std::string& ccdbpath, bool useTimeOffsetCalib, bool useSlewingCalib) : mUseMC(useMC), mCCDBpath(ccdbpath), mUseTimeOffsetCalib(useTimeOffsetCalib), mUseSlewingCalib(useSlewingCalib) {} + ReconstructionDPL(bool useMC, const std::string& ccdbpath, bool useTimeOffsetCalib, bool useSlewingCalib, bool useDeadChannelMap) : mUseMC(useMC), mCCDBpath(ccdbpath), mUseTimeOffsetCalib(useTimeOffsetCalib), mUseSlewingCalib(useSlewingCalib), mUseDeadChannelMap(useDeadChannelMap) {} ~ReconstructionDPL() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -46,6 +46,8 @@ class ReconstructionDPL : public Task bool mUpdateCCDB = true; bool mUseTimeOffsetCalib = true; bool mUseSlewingCalib = true; + bool mUseDeadChannelMap = true; + bool mUpdateDeadChannelMap = true; const std::string mCCDBpath = o2::base::NameConf::getCCDBServer(); std::vector mRecPoints; std::vector mRecChData; @@ -55,7 +57,7 @@ class ReconstructionDPL : public Task }; /// create a processor spec -framework::DataProcessorSpec getReconstructionSpec(bool useMC = false, const std::string ccdbpath = "http://alice-ccdb.cern.ch", bool useTimeOffsetCalib = true, bool useSlewingCalib = true); +framework::DataProcessorSpec getReconstructionSpec(bool useMC = false, const std::string ccdbpath = "http://alice-ccdb.cern.ch", bool useTimeOffsetCalib = true, bool useSlewingCalib = true, bool useDeadChannelMap = true); } // namespace ft0 } // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/src/RecoWorkflow.cxx b/Detectors/FIT/FT0/workflow/src/RecoWorkflow.cxx index 247158164ac3b..2231011febd7f 100644 --- a/Detectors/FIT/FT0/workflow/src/RecoWorkflow.cxx +++ b/Detectors/FIT/FT0/workflow/src/RecoWorkflow.cxx @@ -22,13 +22,13 @@ namespace o2 namespace ft0 { -framework::WorkflowSpec getRecoWorkflow(bool useMC, std::string ccdbpath, bool useTimeOffsetCalib, bool useSlewingCalib, bool disableRootInp, bool disableRootOut) +framework::WorkflowSpec getRecoWorkflow(bool useMC, std::string ccdbpath, bool useTimeOffsetCalib, bool useSlewingCalib, bool disableRootInp, bool disableRootOut, bool useDeadChannelMap) { framework::WorkflowSpec specs; if (!disableRootInp) { specs.emplace_back(o2::ft0::getDigitReaderSpec(useMC)); } - specs.emplace_back(o2::ft0::getReconstructionSpec(useMC, ccdbpath, useTimeOffsetCalib, useSlewingCalib)); + specs.emplace_back(o2::ft0::getReconstructionSpec(useMC, ccdbpath, useTimeOffsetCalib, useSlewingCalib, useDeadChannelMap)); if (!disableRootOut) { specs.emplace_back(o2::ft0::getRecPointWriterSpec(useMC)); } diff --git a/Detectors/FIT/FT0/workflow/src/ReconstructionSpec.cxx b/Detectors/FIT/FT0/workflow/src/ReconstructionSpec.cxx index 40bc96ebca58e..bc5217c8d7471 100644 --- a/Detectors/FIT/FT0/workflow/src/ReconstructionSpec.cxx +++ b/Detectors/FIT/FT0/workflow/src/ReconstructionSpec.cxx @@ -44,6 +44,7 @@ void ReconstructionDPL::init(InitContext& ic) LOG(info) << "FT0 param mMinRMS: " << CalibParam::Instance().mMinRMS; LOG(info) << "FT0 param mMaxSigma: " << CalibParam::Instance().mMaxSigma; LOG(info) << "FT0 param mMaxDiffMean: " << CalibParam::Instance().mMaxDiffMean; + LOG(info) << "FT0 dead channel map will be applied " << mUseDeadChannelMap; } void ReconstructionDPL::run(ProcessingContext& pc) @@ -69,6 +70,12 @@ void ReconstructionDPL::run(ProcessingContext& pc) mReco.SetSlewingCalibObject(slewingCalibObject.get()); } + if (mUseDeadChannelMap && mUpdateDeadChannelMap) { + LOG(debug) << "Applying dead channel map"; + auto deadChannelMap = pc.inputs().get("deadChannelMap"); + mReco.SetDeadChannelMap(deadChannelMap.get()); + } + mRecPoints.reserve(digits.size()); mRecChData.reserve(channels.size()); mReco.processTF(digits, channels, mRecPoints, mRecChData); @@ -91,6 +98,11 @@ void ReconstructionDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) mUseSlewingCalib = false; // upload only once, slewing should be stable during the run return; } + if (matcher == ConcreteDataMatcher("FT0", "DeadChannelMap", 0)) { + LOG(debug) << "New DeadChannelMap is uploaded"; + mUpdateDeadChannelMap = false; + return; + } } void ReconstructionDPL::endOfStream(EndOfStreamContext& ec) @@ -99,12 +111,13 @@ void ReconstructionDPL::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getReconstructionSpec(bool useMC, const std::string ccdbpath, bool useTimeOffsetCalib, bool useSlewingCalib) +DataProcessorSpec getReconstructionSpec(bool useMC, const std::string ccdbpath, bool useTimeOffsetCalib, bool useSlewingCalib, bool useDeadChannelMap) { std::vector inputSpec; std::vector outputSpec; inputSpec.emplace_back("digits", o2::header::gDataOriginFT0, "DIGITSBC", 0, Lifetime::Timeframe); inputSpec.emplace_back("digch", o2::header::gDataOriginFT0, "DIGITSCH", 0, Lifetime::Timeframe); + if (useMC) { LOG(info) << "Currently Reconstruction does not consume and provide MC truth"; inputSpec.emplace_back("labels", o2::header::gDataOriginFT0, "DIGITSMCTR", 0, Lifetime::Timeframe); @@ -121,6 +134,11 @@ DataProcessorSpec getReconstructionSpec(bool useMC, const std::string ccdbpath, ccdbParamSpec("FT0/Calib/SlewingCoef")); } + if (useDeadChannelMap) { + LOG(info) << "Dead channel map will be applied during reconstruction"; + inputSpec.emplace_back("deadChannelMap", o2::header::gDataOriginFT0, "DeadChannelMap", 0, Lifetime::Condition, ccdbParamSpec("FT0/Calib/DeadChannelMap")); + } + outputSpec.emplace_back(o2::header::gDataOriginFT0, "RECPOINTS", 0, Lifetime::Timeframe); outputSpec.emplace_back(o2::header::gDataOriginFT0, "RECCHDATA", 0, Lifetime::Timeframe); @@ -128,7 +146,7 @@ DataProcessorSpec getReconstructionSpec(bool useMC, const std::string ccdbpath, "ft0-reconstructor", inputSpec, outputSpec, - AlgorithmSpec{adaptFromTask(useMC, ccdbpath, useTimeOffsetCalib, useSlewingCalib)}, + AlgorithmSpec{adaptFromTask(useMC, ccdbpath, useTimeOffsetCalib, useSlewingCalib, useDeadChannelMap)}, Options{}}; } diff --git a/Detectors/FIT/FT0/workflow/src/ft0-reco-workflow.cxx b/Detectors/FIT/FT0/workflow/src/ft0-reco-workflow.cxx index 3e6a6bf5da090..ab39068aedb38 100644 --- a/Detectors/FIT/FT0/workflow/src/ft0-reco-workflow.cxx +++ b/Detectors/FIT/FT0/workflow/src/ft0-reco-workflow.cxx @@ -41,7 +41,8 @@ void customize(std::vector& workflowOptions) {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}, {"disable-time-offset-calib", o2::framework::VariantType::Bool, false, {"disable timeoffset calibration"}}, {"disable-slewing-calib", o2::framework::VariantType::Bool, false, {"disable slewing calibration"}}, - {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + {"disable-dead-channel-map", VariantType::Bool, false, {"disable dead channel map"}}}; o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); } @@ -64,9 +65,10 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto disableRootOut = configcontext.options().get("disable-root-output"); const auto useTimeOffsetCalib = !configcontext.options().get("disable-time-offset-calib"); const auto useSlewingCalib = !configcontext.options().get("disable-slewing-calib"); + const auto useDeadChannelMap = !configcontext.options().get("disable-dead-channel-map"); LOG(info) << "WorkflowSpec getRecoWorkflow useMC " << useMC << " CCDB " << ccdbpath; - auto wf = o2::ft0::getRecoWorkflow(useMC, ccdbpath, useTimeOffsetCalib, useSlewingCalib, disableRootInp, disableRootOut); + auto wf = o2::ft0::getRecoWorkflow(useMC, ccdbpath, useTimeOffsetCalib, useSlewingCalib, disableRootInp, disableRootOut, useDeadChannelMap); // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit o2::raw::HBFUtilsInitializer hbfIni(configcontext, wf); diff --git a/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/BaseRecoTask.h b/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/BaseRecoTask.h index 12d89b82a13cc..c5cb5b0da6d05 100644 --- a/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/BaseRecoTask.h +++ b/Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/BaseRecoTask.h @@ -18,6 +18,7 @@ #include "DataFormatsFV0/ChannelData.h" #include "DataFormatsFV0/RecPoints.h" #include "DataFormatsFV0/FV0ChannelTimeCalibrationObject.h" +#include "DataFormatsFIT/DeadChannelMap.h" #include namespace o2 @@ -33,14 +34,15 @@ class BaseRecoTask ~BaseRecoTask() = default; o2::fv0::RecPoints process(o2::fv0::Digit const& bcd, gsl::span inChData, - gsl::span outChData); + std::vector& outChData); void FinishTask(); void SetChannelOffset(o2::fv0::FV0ChannelTimeCalibrationObject const* caliboffsets) { mCalibOffset = caliboffsets; }; + void SetDeadChannelMap(o2::fit::DeadChannelMap const* deadChannelMap) { mDeadChannelMap = deadChannelMap; } int getOffset(int channel); private: o2::fv0::FV0ChannelTimeCalibrationObject const* mCalibOffset = nullptr; - + o2::fit::DeadChannelMap const* mDeadChannelMap = nullptr; ClassDefNV(BaseRecoTask, 3); }; } // namespace fv0 diff --git a/Detectors/FIT/FV0/reconstruction/src/BaseRecoTask.cxx b/Detectors/FIT/FV0/reconstruction/src/BaseRecoTask.cxx index 8a217232592df..8032220f8996d 100644 --- a/Detectors/FIT/FV0/reconstruction/src/BaseRecoTask.cxx +++ b/Detectors/FIT/FV0/reconstruction/src/BaseRecoTask.cxx @@ -27,7 +27,7 @@ using RP = o2::fv0::RecPoints; RP BaseRecoTask::process(o2::fv0::Digit const& bcd, gsl::span inChData, - gsl::span outChData) + std::vector& outChData) { LOG(debug) << "Running reconstruction on new event"; @@ -44,22 +44,27 @@ RP BaseRecoTask::process(o2::fv0::Digit const& bcd, int nch = inChData.size(); for (int ich = 0; ich < nch; ich++) { LOG(debug) << " channel " << ich << " / " << nch; + if (mDeadChannelMap && !mDeadChannelMap->isChannelAlive(inChData[ich].ChId)) { + LOG(debug) << "Channel " << ich << " is dead - discarding data"; + continue; + } int offsetChannel = getOffset(int(inChData[ich].ChId)); - outChData[ich] = o2::fv0::ChannelDataFloat{inChData[ich].ChId, - (inChData[ich].CFDTime - offsetChannel) * DigitizationConstant::TIME_PER_TDCCHANNEL, - (float)inChData[ich].QTCAmpl, - inChData[ich].ChainQTC}; + outChData.emplace_back(o2::fv0::ChannelDataFloat{inChData[ich].ChId, + (inChData[ich].CFDTime - offsetChannel) * DigitizationConstant::TIME_PER_TDCCHANNEL, + (float)inChData[ich].QTCAmpl, + inChData[ich].ChainQTC}); + const auto& currentOutCh = outChData.back(); // Conditions for reconstructing collision time (3 variants: first, average-relaxed and average-tight) - if (outChData[ich].charge > FV0DigParam::Instance().chargeThrForMeanTime) { - sideAtimeFirst = std::min(static_cast(sideAtimeFirst), outChData[ich].time); + if (currentOutCh.charge > FV0DigParam::Instance().chargeThrForMeanTime) { + sideAtimeFirst = std::min(static_cast(sideAtimeFirst), currentOutCh.time); if (inChData[ich].areAllFlagsGood()) { - if (std::abs(outChData[ich].time) < FV0DigParam::Instance().mTimeThresholdForReco) { - sideAtimeAvg += outChData[ich].time; + if (std::abs(currentOutCh.time) < FV0DigParam::Instance().mTimeThresholdForReco) { + sideAtimeAvg += currentOutCh.time; ndigitsA++; } - if (outChData[ich].charge > FV0DigParam::Instance().mAmpThresholdForReco && std::abs(outChData[ich].time) < FV0DigParam::Instance().mTimeThresholdForReco) { - sideAtimeAvgSelected += outChData[ich].time; + if (currentOutCh.charge > FV0DigParam::Instance().mAmpThresholdForReco && std::abs(currentOutCh.time) < FV0DigParam::Instance().mTimeThresholdForReco) { + sideAtimeAvgSelected += currentOutCh.time; ndigitsASelected++; } } diff --git a/Detectors/FIT/FV0/workflow/include/FV0Workflow/RecoWorkflow.h b/Detectors/FIT/FV0/workflow/include/FV0Workflow/RecoWorkflow.h index 015870d9178e2..f035b2406e5ba 100644 --- a/Detectors/FIT/FV0/workflow/include/FV0Workflow/RecoWorkflow.h +++ b/Detectors/FIT/FV0/workflow/include/FV0Workflow/RecoWorkflow.h @@ -20,7 +20,7 @@ namespace o2 { namespace fv0 { -framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut); +framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut, bool useDeadChannelMap); } // namespace fv0 } // namespace o2 #endif diff --git a/Detectors/FIT/FV0/workflow/include/FV0Workflow/ReconstructionSpec.h b/Detectors/FIT/FV0/workflow/include/FV0Workflow/ReconstructionSpec.h index d71e154280e3d..934ce4d2c4a66 100644 --- a/Detectors/FIT/FV0/workflow/include/FV0Workflow/ReconstructionSpec.h +++ b/Detectors/FIT/FV0/workflow/include/FV0Workflow/ReconstructionSpec.h @@ -34,7 +34,7 @@ class ReconstructionDPL : public Task static constexpr int NCHANNELS = o2::fv0::Constants::nFv0Channels; public: - ReconstructionDPL(bool useMC, const std::string ccdbpath) : mUseMC(useMC), mCCDBpath(ccdbpath) {} + ReconstructionDPL(bool useMC, bool useDeadChannelMap, const std::string ccdbpath) : mUseMC(useMC), mUseDeadChannelMap(useDeadChannelMap), mCCDBpath(ccdbpath) {} ~ReconstructionDPL() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -44,6 +44,8 @@ class ReconstructionDPL : public Task private: bool mUseMC = false; bool mUpdateCCDB = true; + bool mUseDeadChannelMap = true; + bool mUpdateDeadChannelMap = true; const std::string mCCDBpath = o2::base::NameConf::getCCDBServer(); std::vector mRecPoints; std::vector mRecChData; @@ -53,7 +55,7 @@ class ReconstructionDPL : public Task }; /// create a processor spec -framework::DataProcessorSpec getReconstructionSpec(bool useMC = false, const std::string ccdbpath = "http://alice-ccdb.cern.ch"); +framework::DataProcessorSpec getReconstructionSpec(bool useMC = false, bool useDeadChannelMap = true, const std::string ccdbpath = "http://alice-ccdb.cern.ch"); } // namespace fv0 } // namespace o2 diff --git a/Detectors/FIT/FV0/workflow/src/RecoWorkflow.cxx b/Detectors/FIT/FV0/workflow/src/RecoWorkflow.cxx index 6bfc5479303d1..a0ef71b75765a 100644 --- a/Detectors/FIT/FV0/workflow/src/RecoWorkflow.cxx +++ b/Detectors/FIT/FV0/workflow/src/RecoWorkflow.cxx @@ -22,14 +22,13 @@ namespace o2 namespace fv0 { -framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut) +framework::WorkflowSpec getRecoWorkflow(bool useMC, bool disableRootInp, bool disableRootOut, bool useDeadChannelMap) { framework::WorkflowSpec specs; if (!disableRootInp) { specs.emplace_back(o2::fv0::getDigitReaderSpec(useMC)); } - - specs.emplace_back(o2::fv0::getReconstructionSpec(useMC)); + specs.emplace_back(o2::fv0::getReconstructionSpec(useMC, useDeadChannelMap)); if (!disableRootOut) { specs.emplace_back(o2::fv0::getRecPointWriterSpec(useMC)); } diff --git a/Detectors/FIT/FV0/workflow/src/ReconstructionSpec.cxx b/Detectors/FIT/FV0/workflow/src/ReconstructionSpec.cxx index 520ac4dbaa563..b97186bbf81a8 100644 --- a/Detectors/FIT/FV0/workflow/src/ReconstructionSpec.cxx +++ b/Detectors/FIT/FV0/workflow/src/ReconstructionSpec.cxx @@ -21,6 +21,7 @@ #include "DataFormatsFV0/ChannelData.h" #include "DataFormatsFV0/MCLabel.h" #include "DataFormatsFV0/FV0ChannelTimeCalibrationObject.h" +#include "DataFormatsFIT/DeadChannelMap.h" #include "Framework/CCDBParamSpec.h" using namespace o2::framework; @@ -53,18 +54,19 @@ void ReconstructionDPL::run(ProcessingContext& pc) auto caliboffsets = pc.inputs().get("fv0offsets"); mReco.SetChannelOffset(caliboffsets.get()); } + if (mUseDeadChannelMap && mUpdateDeadChannelMap) { + auto deadChannelMap = pc.inputs().get("deadChannelMap"); + mReco.SetDeadChannelMap(deadChannelMap.get()); + } int nDig = digits.size(); LOG(debug) << " nDig " << nDig << " | ndigch " << digch.size(); mRecPoints.reserve(nDig); - mRecChData.resize(digch.size()); for (int id = 0; id < nDig; id++) { const auto& digit = digits[id]; LOG(debug) << " ndig " << id << " bc " << digit.getBC() << " orbit " << digit.getOrbit(); auto channels = digit.getBunchChannelData(digch); - gsl::span out_ch(mRecChData); - out_ch = out_ch.subspan(digit.ref.getFirstEntry(), digit.ref.getEntries()); - mRecPoints.emplace_back(mReco.process(digit, channels, out_ch)); + mRecPoints.emplace_back(mReco.process(digit, channels, mRecChData)); } LOG(debug) << "FV0 reconstruction pushes " << mRecPoints.size() << " RecPoints"; @@ -80,6 +82,9 @@ void ReconstructionDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) mUpdateCCDB = false; return; } + if (matcher == ConcreteDataMatcher(o2::header::gDataOriginFV0, "DeadChannelMap", 0)) { + mUpdateDeadChannelMap = false; + } } void ReconstructionDPL::endOfStream(EndOfStreamContext& ec) @@ -88,7 +93,7 @@ void ReconstructionDPL::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getReconstructionSpec(bool useMC, const std::string ccdbpath) +DataProcessorSpec getReconstructionSpec(bool useMC, bool useDeadChannelMap, const std::string ccdbpath) { std::vector inputSpec; std::vector outputSpec; @@ -98,6 +103,10 @@ DataProcessorSpec getReconstructionSpec(bool useMC, const std::string ccdbpath) LOG(info) << "Currently Reconstruction does not consume and provide MC truth"; inputSpec.emplace_back("labels", o2::header::gDataOriginFV0, "DIGITSMCTR", 0, Lifetime::Timeframe); } + if (useDeadChannelMap) { + LOG(info) << "Dead channel map will be applied during reconstruction"; + inputSpec.emplace_back("deadChannelMap", o2::header::gDataOriginFV0, "DeadChannelMap", 0, Lifetime::Condition, ccdbParamSpec("FV0/Calib/DeadChannelMap")); + } inputSpec.emplace_back("fv0offsets", "FV0", "TimeOffset", 0, Lifetime::Condition, ccdbParamSpec("FV0/Calib/ChannelTimeOffset")); @@ -109,7 +118,7 @@ DataProcessorSpec getReconstructionSpec(bool useMC, const std::string ccdbpath) "fv0-reconstructor", inputSpec, outputSpec, - AlgorithmSpec{adaptFromTask(useMC, ccdbpath)}, + AlgorithmSpec{adaptFromTask(useMC, useDeadChannelMap, ccdbpath)}, Options{}}; } diff --git a/Detectors/FIT/FV0/workflow/src/fv0-reco-workflow.cxx b/Detectors/FIT/FV0/workflow/src/fv0-reco-workflow.cxx index 16d1383c7e8c4..309560e2d6b36 100644 --- a/Detectors/FIT/FV0/workflow/src/fv0-reco-workflow.cxx +++ b/Detectors/FIT/FV0/workflow/src/fv0-reco-workflow.cxx @@ -39,6 +39,7 @@ void customize(std::vector& workflowOptions) {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}, {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input readers"}}, {"disable-root-output", o2::framework::VariantType::Bool, false, {"disable root-files output writers"}}, + {"disable-dead-channel-map", o2::framework::VariantType::Bool, false, {"disable dead channel map"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}}; o2::raw::HBFUtilsInitializer::addConfigOption(options); std::swap(workflowOptions, options); @@ -59,9 +60,10 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto useMC = !configcontext.options().get("disable-mc"); auto disableRootInp = configcontext.options().get("disable-root-input"); auto disableRootOut = configcontext.options().get("disable-root-output"); + bool useDeadChannelMap = !configcontext.options().get("disable-dead-channel-map"); LOG(info) << "WorkflowSpec getRecoWorkflow useMC " << useMC; - auto wf = o2::fv0::getRecoWorkflow(useMC, disableRootInp, disableRootOut); + auto wf = o2::fv0::getRecoWorkflow(useMC, disableRootInp, disableRootOut, useDeadChannelMap); // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit o2::raw::HBFUtilsInitializer hbfIni(configcontext, wf); From 3e6876861dffa4a73c9c7fd8c858d6f7cb3f9554 Mon Sep 17 00:00:00 2001 From: Maximiliano Puccio Date: Mon, 16 Feb 2026 16:03:27 +0100 Subject: [PATCH 208/234] First version of the hit based CA tracker for ALICE3 IT/OT (#15066) * ITSTracking: change visibility of methods Change TimeFrame prepareClusters method visibility to protected Add computeTracksMClabels method to Tracker class * Hit based CA for ALICE3 tracker --- .../tracking/include/ITStracking/TimeFrame.h | 2 +- .../tracking/include/ITStracking/Tracker.h | 2 +- Detectors/Upgrades/ALICE3/TRK/CMakeLists.txt | 3 +- .../ALICE3/TRK/macros/test/CMakeLists.txt | 10 + .../ALICE3/TRK/macros/test/CheckTracksCA.C | 345 ++++++++++++++++++ .../ALICE3/TRK/reconstruction/CMakeLists.txt | 34 ++ .../include/TRKReconstruction/TimeFrame.h | 73 ++++ .../src/TRKReconstructionLinkDef.h | 20 + .../TRK/reconstruction/src/TimeFrame.cxx | 189 ++++++++++ .../ALICE3/TRK/workflow/CMakeLists.txt | 10 +- .../Upgrades/ALICE3/TRK/workflow/README.md | 130 +++++++ .../include/TRKWorkflow/RecoWorkflow.h | 2 + .../include/TRKWorkflow/TrackWriterSpec.h | 31 ++ .../include/TRKWorkflow/TrackerSpec.h | 12 +- .../ALICE3/TRK/workflow/src/RecoWorkflow.cxx | 11 +- .../TRK/workflow/src/TrackWriterSpec.cxx | 57 +++ .../ALICE3/TRK/workflow/src/TrackerSpec.cxx | 336 ++++++++++++++++- .../TRK/workflow/src/trk-reco-workflow.cxx | 4 +- 18 files changed, 1251 insertions(+), 20 deletions(-) create mode 100644 Detectors/Upgrades/ALICE3/TRK/macros/test/CheckTracksCA.C create mode 100644 Detectors/Upgrades/ALICE3/TRK/reconstruction/CMakeLists.txt create mode 100644 Detectors/Upgrades/ALICE3/TRK/reconstruction/include/TRKReconstruction/TimeFrame.h create mode 100644 Detectors/Upgrades/ALICE3/TRK/reconstruction/src/TRKReconstructionLinkDef.h create mode 100644 Detectors/Upgrades/ALICE3/TRK/reconstruction/src/TimeFrame.cxx create mode 100644 Detectors/Upgrades/ALICE3/TRK/workflow/README.md create mode 100644 Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/TrackWriterSpec.h create mode 100644 Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackWriterSpec.cxx diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h index 4dbb9f09f6192..acc884ea68b8b 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h @@ -299,7 +299,7 @@ struct TimeFrame { virtual bool isGPU() const noexcept { return false; } virtual const char* getName() const noexcept { return "CPU"; } - private: + protected: void prepareClusters(const TrackingParameters& trkParam, const int maxLayers = nLayers); float mBz = 5.; unsigned int mNTotalLowPtVertices = 0; diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracker.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracker.h index 4c903ed1f3ca1..3ea382c626fed 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracker.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracker.h @@ -72,6 +72,7 @@ class Tracker bool isMatLUT() const { return mTraits->isMatLUT(); } void setNThreads(int n, std::shared_ptr& arena) { mTraits->setNThreads(n, arena); } void printSummary() const; + void computeTracksMClabels(); private: void initialiseTimeFrame(int iteration) { mTraits->initialiseTimeFrame(iteration); } @@ -84,7 +85,6 @@ class Tracker // MC interaction void computeRoadsMClabels(); - void computeTracksMClabels(); void rectifyClusterIndices(); template diff --git a/Detectors/Upgrades/ALICE3/TRK/CMakeLists.txt b/Detectors/Upgrades/ALICE3/TRK/CMakeLists.txt index e623239122658..6e3437c9d841b 100644 --- a/Detectors/Upgrades/ALICE3/TRK/CMakeLists.txt +++ b/Detectors/Upgrades/ALICE3/TRK/CMakeLists.txt @@ -12,4 +12,5 @@ add_subdirectory(base) add_subdirectory(macros) add_subdirectory(simulation) -add_subdirectory(workflow) \ No newline at end of file +add_subdirectory(reconstruction) +add_subdirectory(workflow) diff --git a/Detectors/Upgrades/ALICE3/TRK/macros/test/CMakeLists.txt b/Detectors/Upgrades/ALICE3/TRK/macros/test/CMakeLists.txt index 379207eb07481..d9908bbfeb1e5 100644 --- a/Detectors/Upgrades/ALICE3/TRK/macros/test/CMakeLists.txt +++ b/Detectors/Upgrades/ALICE3/TRK/macros/test/CMakeLists.txt @@ -18,4 +18,14 @@ o2_add_test_root_macro(CheckDigits.C O2::SimulationDataFormat O2::DetectorsBase O2::Steer + LABELS trk COMPILE_ONLY) + +o2_add_test_root_macro(CheckTracksCA.C + PUBLIC_LINK_LIBRARIES O2::DataFormatsITS + O2::ITStracking + O2::SimulationDataFormat + O2::DetectorsBase + O2::TRKBase + O2::TRKSimulation + O2::Steer LABELS trk COMPILE_ONLY) \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/TRK/macros/test/CheckTracksCA.C b/Detectors/Upgrades/ALICE3/TRK/macros/test/CheckTracksCA.C new file mode 100644 index 0000000000000..ae75616b7719c --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/macros/test/CheckTracksCA.C @@ -0,0 +1,345 @@ +// 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 CheckTracksCA.C +/// \brief Quality assurance macro for TRK tracking + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DataFormatsITS/TrackITS.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTrack.h" +#include "Steer/MCKinematicsReader.h" +#include "TRKSimulation/Hit.h" +#include "TRKBase/GeometryTGeo.h" +#include "DetectorsBase/GeometryManager.h" + +#endif + +using namespace std; +using namespace o2; + +/// Structure to track particle hit information +struct ParticleHitInfo { + std::bitset<11> layerHits; ///< Which layers have hits (11 layers for TRK) + int nHits = 0; ///< Total number of hits + float pt = 0.0f; ///< Particle pT + + void addHit(int layer) + { + if (!layerHits[layer]) { + layerHits[layer] = true; + nHits++; + } + } + + bool hasConsecutiveLayers(int nConsecutive) const + { + for (int startLayer = 0; startLayer <= 11 - nConsecutive; ++startLayer) { + bool allSet = true; + for (int i = 0; i < nConsecutive; ++i) { + if (!layerHits[startLayer + i]) { + allSet = false; + break; + } + } + if (allSet) { + return true; + } + } + return false; + } +}; + +void CheckTracksCA(std::string tracfile = "o2trac_trk.root", + std::string kinefile = "o2sim_Kine.root", + std::string hitsfile = "o2sim_HitsTRK.root", + std::string outputfile = "trk_qa_output.root") +{ + gStyle->SetOptStat(0); + + std::cout << "=== Starting TRK Track Quality Assurance ===" << std::endl; + std::cout << "Input files:" << std::endl; + std::cout << " Tracks: " << tracfile << std::endl; + std::cout << " Kinematics: " << kinefile << std::endl; + std::cout << " Hits: " << hitsfile << std::endl; + std::cout << " Output: " << outputfile << std::endl; + std::cout << std::endl; + + // MC kinematics reader + o2::steer::MCKinematicsReader kineReader("o2sim", o2::steer::MCKinematicsReader::Mode::kMCKine); + const int nEvents = kineReader.getNEvents(0); + std::cout << "Number of MC events: " << nEvents << std::endl; + + // Open hits file to count hits per particle per layer + TFile* hitsFile = TFile::Open(hitsfile.c_str(), "READ"); + if (!hitsFile || hitsFile->IsZombie()) { + std::cerr << "ERROR: Cannot open hits file: " << hitsfile << std::endl; + return; + } + TTree* hitsTree = hitsFile->Get("o2sim"); + if (!hitsTree) { + std::cerr << "ERROR: Cannot find o2sim tree in hits file" << std::endl; + return; + } + + // Open reconstructed tracks file + TFile* tracFile = TFile::Open(tracfile.c_str(), "READ"); + if (!tracFile || tracFile->IsZombie()) { + std::cerr << "ERROR: Cannot open tracks file: " << tracfile << std::endl; + return; + } + TTree* recTree = tracFile->Get("o2sim"); + if (!recTree) { + std::cerr << "ERROR: Cannot find o2sim tree in tracks file" << std::endl; + return; + } + + // Reconstructed tracks and labels + std::vector* recTracks = nullptr; + std::vector* trkLabels = nullptr; + recTree->SetBranchAddress("TRKTrack", &recTracks); + recTree->SetBranchAddress("TRKTrackMCTruth", &trkLabels); + + std::cout << "Reading tracks from tree..." << std::endl; + + // Analyze hits tree to count hits per particle per layer + std::cout << "Analyzing hits from tree..." << std::endl; + std::unordered_map particleHitMap; + + // Load geometry for layer determination + o2::base::GeometryManager::loadGeometry(); + auto* gman = o2::trk::GeometryTGeo::Instance(); + + // Array to map detector to starting layer + constexpr std::array startLayer{0, 3}; + + std::vector* trkHit = nullptr; + hitsTree->SetBranchAddress("TRKHit", &trkHit); + + Long64_t nHitsEntries = hitsTree->GetEntries(); + std::cout << "Processing " << nHitsEntries << " hit entries..." << std::endl; + + for (Long64_t iEntry = 0; iEntry < nHitsEntries; ++iEntry) { + hitsTree->GetEntry(iEntry); + + for (const auto& hit : *trkHit) { + // Skip disk hits (only barrel) + if (gman->getDisk(hit.GetDetectorID()) != -1) { + continue; + } + + // Determine layer + int subDetID = gman->getSubDetID(hit.GetDetectorID()); + const int layer = startLayer[subDetID] + gman->getLayer(hit.GetDetectorID()); + + // Create label for this particle + o2::MCCompLabel label(hit.GetTrackID(), static_cast(iEntry), 0); + + // Add hit to particle's hit map + particleHitMap[label].addHit(layer); + } + } + + std::cout << "Found " << particleHitMap.size() << " unique particles with hits" << std::endl; + + // Store particle info and fill generated histograms + std::unordered_map particlePtMap; + + // Create histograms + constexpr int nLayers = 11; + constexpr int nb = 100; + double xbins[nb + 1], ptcutl = 0.05, ptcuth = 10.; + double a = std::log(ptcuth / ptcutl) / nb; + for (int i = 0; i <= nb; i++) + xbins[i] = ptcutl * std::exp(i * a); + + TH1D genParticlePtHist("genParticlePt", "Generated Particle p_{T} (All Layers); #it{p}_{T} (GeV/#it{c}); Counts", nb, xbins); + TH1D genParticlePt7LayersHist("genParticlePt7Layers", "Generated Particle p_{T} with hits in at least 7 consecutive layers; #it{p}_{T} (GeV/#it{c}); Counts", nb, xbins); + TH1D goodTracks("goodTracks", "Good Tracks; p_{T} (GeV/c); Counts", nb, xbins); + TH1D fakeTracks("fakeTracks", "Fake Tracks; p_{T} (GeV/c); Counts", nb, xbins); + + std::array goodTracksMatching, fakeTracksMatching; + for (int i = 0; i < 5; ++i) { + goodTracksMatching[i] = TH1D(Form("goodTracksMatching_%dLayers", i + 7), + Form("Good Tracks with %d layer hits; p_{T} (GeV/c); Counts", i + 7), + nb, xbins); + fakeTracksMatching[i] = TH1D(Form("fakeTracksMatching_%dLayers", i + 7), + Form("Fake Tracks with %d layer hits; p_{T} (GeV/c); Counts", i + 7), + nb, xbins); + } + + TH1D numberOfClustersPerTrack("numberOfClustersPerTrack", + "Number of clusters per track; N_{clusters}; Counts", + 12, -0.5, 11.5); + + // First pass: identify particles with full hit coverage from kinematics + std::cout << "Analyzing MC particles..." << std::endl; + for (int iEvent = 0; iEvent < nEvents; ++iEvent) { + const auto& mcTracks = kineReader.getTracks(iEvent); + for (size_t iTrack = 0; iTrack < mcTracks.size(); ++iTrack) { + const auto& mcTrack = mcTracks[iTrack]; + if (!mcTrack.isPrimary()) { + continue; + } + + // Create label for this particle + o2::MCCompLabel label(iTrack, iEvent, 0); + float pt = mcTrack.GetPt(); + + // Store particle info + particlePtMap[label] = pt; + + // Check if this particle has hits + auto hitIt = particleHitMap.find(label); + if (hitIt != particleHitMap.end()) { + // Store pT in hit info + hitIt->second.pt = pt; + + // Fill histogram for particles with hits in all 11 layers + if (hitIt->second.nHits == 11) { + genParticlePtHist.Fill(pt); + } + + // Fill histogram for particles with at least 7 consecutive layer hits + if (hitIt->second.hasConsecutiveLayers(7)) { + genParticlePt7LayersHist.Fill(pt); + } + } + } + } + + std::cout << "Generated particles with 11 hits: " << genParticlePtHist.GetEntries() << std::endl; + std::cout << "Generated particles with 7+ consecutive hits: " << genParticlePt7LayersHist.GetEntries() << std::endl; + + // Second pass: analyze reconstructed tracks + std::cout << "Analyzing reconstructed tracks..." << std::endl; + int nROFs = recTree->GetEntries(); + int totalTracks = 0; + int goodTracksCount = 0; + int fakeTracksCount = 0; + + for (int iROF = 0; iROF < nROFs; ++iROF) { + recTree->GetEntry(iROF); + + if (!recTracks || !trkLabels) { + continue; + } + + totalTracks += recTracks->size(); + + for (size_t iTrack = 0; iTrack < recTracks->size(); ++iTrack) { + const auto& track = recTracks->at(iTrack); + const auto& label = trkLabels->at(iTrack); + + if (!label.isSet() || !label.isValid()) { + continue; + } + + int eventID = label.getEventID(); + int trackID = label.getTrackID(); + int nClusters = track.getNumberOfClusters(); + + // Get MC track info + if (eventID < 0 || eventID >= nEvents) { + continue; + } + + const auto& mcTracks = kineReader.getTracks(eventID); + if (trackID < 0 || trackID >= (int)mcTracks.size()) { + continue; + } + + float pt = mcTracks[trackID].GetPt(); + + // Fill histograms + numberOfClustersPerTrack.Fill(nClusters); + + auto key = o2::MCCompLabel(trackID, eventID, 0); + if (particleHitMap.find(key) != particleHitMap.end() && particleHitMap[key].hasConsecutiveLayers(11)) { + if (label.isFake()) { + fakeTracks.Fill(pt); + fakeTracksCount++; + if (nClusters >= 7 && nClusters <= 11) { + fakeTracksMatching[nClusters - 7].Fill(pt); + } + } else { + goodTracks.Fill(pt); + goodTracksCount++; + if (nClusters >= 7 && nClusters <= 11) { + goodTracksMatching[nClusters - 7].Fill(pt); + } + } + } + } + } + + // Create efficiency histograms + std::cout << "Computing efficiencies..." << std::endl; + + std::array efficiencyHistograms; + THStack* efficiencyStack = new THStack("efficiencyStack", + "Tracking Efficiency; #it{p}_{T} (GeV/#it{c}); Efficiency"); + + int colors[5] = {kRed, kBlue, kGreen + 2, kMagenta, kOrange}; + for (int i = 0; i < 5; ++i) { + int nClusters = i + 7; + efficiencyHistograms[i] = TH1D(Form("efficiency_%dClusters", nClusters), + Form("Efficiency for %d cluster tracks; #it{p}_{T} (GeV/#it{c}); Efficiency", nClusters), + nb, xbins); + + efficiencyHistograms[i].Divide(&goodTracksMatching[i], &genParticlePtHist, 1, 1, "B"); + + efficiencyHistograms[i].SetLineColor(colors[i]); + efficiencyHistograms[i].SetFillColor(colors[i]); + efficiencyHistograms[i].SetLineWidth(2); + efficiencyHistograms[i].SetMarkerColor(colors[i]); + efficiencyHistograms[i].SetMarkerStyle(20 + i); + efficiencyStack->Add(&efficiencyHistograms[i]); + } + + // Write output + std::cout << "Writing output to " << outputfile << std::endl; + TFile outFile(outputfile.c_str(), "RECREATE"); + genParticlePtHist.Write(); + goodTracks.Write(); + fakeTracks.Write(); + for (int i = 0; i < 5; ++i) { + goodTracksMatching[i].Write(); + fakeTracksMatching[i].Write(); + efficiencyHistograms[i].Write(); + } + efficiencyStack->Write(); + genParticlePt7LayersHist.Write(); + numberOfClustersPerTrack.Write(); + outFile.Close(); + + // Clean up + hitsFile->Close(); + tracFile->Close(); + delete efficiencyStack; + delete hitsFile; + delete tracFile; +} diff --git a/Detectors/Upgrades/ALICE3/TRK/reconstruction/CMakeLists.txt b/Detectors/Upgrades/ALICE3/TRK/reconstruction/CMakeLists.txt new file mode 100644 index 0000000000000..01ddc783d192b --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/reconstruction/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +o2_add_library(TRKReconstruction + TARGETVARNAME targetName + SOURCES src/TimeFrame.cxx + PUBLIC_LINK_LIBRARIES + O2::ITStracking + O2::GPUCommon + Microsoft.GSL::GSL + O2::CommonConstants + O2::DataFormatsITSMFT + O2::SimulationDataFormat + O2::ITSBase + O2::ITSReconstruction + O2::ITSMFTReconstruction + O2::DataFormatsITS + O2::TRKSimulation + nlohmann_json::nlohmann_json + PRIVATE_LINK_LIBRARIES + O2::Steer + TBB::tbb) + +o2_target_root_dictionary(TRKReconstruction + HEADERS include/TRKReconstruction/TimeFrame.h + LINKDEF src/TRKReconstructionLinkDef.h) diff --git a/Detectors/Upgrades/ALICE3/TRK/reconstruction/include/TRKReconstruction/TimeFrame.h b/Detectors/Upgrades/ALICE3/TRK/reconstruction/include/TRKReconstruction/TimeFrame.h new file mode 100644 index 0000000000000..d2ca6fba132e1 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/reconstruction/include/TRKReconstruction/TimeFrame.h @@ -0,0 +1,73 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file TimeFrame.h +/// \brief TRK TimeFrame class derived from ITS TimeFrame +/// + +#ifndef ALICEO2_TRK_TIMEFRAME_H +#define ALICEO2_TRK_TIMEFRAME_H + +#include "ITStracking/TimeFrame.h" +#include "ITStracking/Constants.h" +#include "ITStracking/Configuration.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include +#include +#include +#include + +#include + +class TTree; + +namespace o2 +{ +namespace trk +{ +class Hit; +class GeometryTGeo; + +/// TRK TimeFrame class that extends ITS TimeFrame functionality +/// This allows for customization of tracking algorithms specific to the TRK detector +template +class TimeFrame : public o2::its::TimeFrame +{ + public: + TimeFrame() = default; + ~TimeFrame() override = default; + + /// Override methods if needed for TRK-specific behavior + /// For now, we inherit all functionality from ITS TimeFrame + + /// Process hits from TTree to initialize ROFs + /// \param hitsTree Tree containing TRK hits + /// \param mcHeaderTree Tree containing MC event headers + /// \param nEvents Number of events to process + /// \param gman TRK geometry manager instance + /// \param config Configuration parameters for hit reconstruction + int loadROFsFromHitTree(TTree* hitsTree, GeometryTGeo* gman, const nlohmann::json& config); + + /// Add primary vertices from MC headers for each ROF + /// \param mcHeaderTree Tree containing MC event headers + /// \param nRofs Number of ROFs (Read-Out Frames) + /// \param nEvents Number of events to process + /// \param inROFpileup Number of events per ROF + void getPrimaryVerticesFromMC(TTree* mcHeaderTree, int nRofs, Long64_t nEvents, int inROFpileup); + + private: + ClassDefNV(TimeFrame, 1); +}; + +} // namespace trk +} // namespace o2 + +#endif // ALICEO2_TRK_TIMEFRAME_H diff --git a/Detectors/Upgrades/ALICE3/TRK/reconstruction/src/TRKReconstructionLinkDef.h b/Detectors/Upgrades/ALICE3/TRK/reconstruction/src/TRKReconstructionLinkDef.h new file mode 100644 index 0000000000000..09ab598ec626c --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/reconstruction/src/TRKReconstructionLinkDef.h @@ -0,0 +1,20 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class o2::trk::TimeFrame < 11> + ; + +#endif diff --git a/Detectors/Upgrades/ALICE3/TRK/reconstruction/src/TimeFrame.cxx b/Detectors/Upgrades/ALICE3/TRK/reconstruction/src/TimeFrame.cxx new file mode 100644 index 0000000000000..686270826049b --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/reconstruction/src/TimeFrame.cxx @@ -0,0 +1,189 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +/// +/// \file TimeFrame.cxx +/// \brief TRK TimeFrame implementation +/// + +#include "TRKReconstruction/TimeFrame.h" +#include "TRKSimulation/Hit.h" +#include "TRKBase/GeometryTGeo.h" +#include "Framework/Logger.h" +#include "SimulationDataFormat/MCEventHeader.h" +#include +#include +#include +#include + +namespace o2::trk +{ + +template +int TimeFrame::loadROFsFromHitTree(TTree* hitsTree, GeometryTGeo* gman, const nlohmann::json& config) +{ + constexpr std::array startLayer{0, 3}; + const Long64_t nEvents = hitsTree->GetEntries(); + + gman->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L) | o2::math_utils::bit2Mask(o2::math_utils::TransformType::L2G)); + + std::vector* trkHit = nullptr; + hitsTree->SetBranchAddress("TRKHit", &trkHit); + + const int inROFpileup{config.contains("inROFpileup") ? config["inROFpileup"].get() : 1}; + + // Calculate number of ROFs and initialize data structures + this->mNrof = (nEvents + inROFpileup - 1) / inROFpileup; + + // Reset and prepare ROF data structures + for (int iLayer{0}; iLayer < nLayers; ++iLayer) { + this->mMinR[iLayer] = std::numeric_limits::max(); + this->mMaxR[iLayer] = std::numeric_limits::lowest(); + this->mROFramesClusters[iLayer].clear(); + this->mROFramesClusters[iLayer].resize(this->mNrof + 1, 0); + this->mUnsortedClusters[iLayer].clear(); + this->mTrackingFrameInfo[iLayer].clear(); + this->mClusterExternalIndices[iLayer].clear(); + } + + // Pre-count hits to reserve memory efficiently + int totalNHits{0}; + std::array clusterCountPerLayer{}; + for (Long64_t iEvent = 0; iEvent < nEvents; ++iEvent) { + hitsTree->GetEntry(iEvent); + for (const auto& hit : *trkHit) { + if (gman->getDisk(hit.GetDetectorID()) != -1) { + continue; // skip non-barrel hits + } + int subDetID = gman->getSubDetID(hit.GetDetectorID()); + const int layer = startLayer[subDetID] + gman->getLayer(hit.GetDetectorID()); + ++clusterCountPerLayer[layer]; + totalNHits++; + } + trkHit->clear(); + } + + // Reserve memory for all layers + for (int iLayer{0}; iLayer < nLayers; ++iLayer) { + this->mUnsortedClusters[iLayer].reserve(clusterCountPerLayer[iLayer]); + this->mTrackingFrameInfo[iLayer].reserve(clusterCountPerLayer[iLayer]); + this->mClusterExternalIndices[iLayer].reserve(clusterCountPerLayer[iLayer]); + } + clearResizeBoundedVector(this->mClusterSize, totalNHits, this->mMemoryPool.get()); + + std::array resolution{0.001, 0.001, 0.001, 0.001, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004}; + if (config["geometry"]["pitch"].size() == nLayers) { + for (int iLayer{0}; iLayer < config["geometry"]["pitch"].size(); ++iLayer) { + LOGP(info, "Setting resolution for layer {} from config", iLayer); + LOGP(info, "Layer {} pitch {} cm", iLayer, config["geometry"]["pitch"][iLayer].get()); + resolution[iLayer] = config["geometry"]["pitch"][iLayer].get() / std::sqrt(12.f); + } + } + LOGP(info, "Number of active parts in VD: {}", gman->getNumberOfActivePartsVD()); + + int hitCounter{0}; + auto labels = new dataformats::MCTruthContainer(); + + int iRof{0}; // Current ROF index + for (Long64_t iEvent = 0; iEvent < nEvents; ++iEvent) { + hitsTree->GetEntry(iEvent); + + for (auto& hit : *trkHit) { + if (gman->getDisk(hit.GetDetectorID()) != -1) { + continue; // skip non-barrel hits for this test + } + int subDetID = gman->getSubDetID(hit.GetDetectorID()); + const int layer = startLayer[subDetID] + gman->getLayer(hit.GetDetectorID()); + + float alpha{0.f}; + o2::math_utils::Point3D gloXYZ; + o2::math_utils::Point3D trkXYZ; + float r{0.f}; + if (layer >= 3) { + int chipID = hit.GetDetectorID(); + alpha = gman->getSensorRefAlphaMLOT(chipID); + const o2::math_utils::Transform3D& l2g = gman->getMatrixL2G(chipID); + auto locXYZ = l2g ^ (hit.GetPos()); + locXYZ.SetX(locXYZ.X() + gRandom->Gaus(0.0, resolution[layer])); + locXYZ.SetZ(locXYZ.Z() + gRandom->Gaus(0.0, resolution[layer])); + gloXYZ = gman->getMatrixL2G(chipID) * locXYZ; + trkXYZ = gman->getMatrixT2L(chipID - gman->getNumberOfActivePartsVD()) ^ locXYZ; + r = std::hypot(gloXYZ.X(), gloXYZ.Y()); + } else { + const auto& hitPos = hit.GetPos(); + r = std::hypot(hitPos.X(), hitPos.Y()); + alpha = std::atan2(hitPos.Y(), hitPos.X()) + gRandom->Gaus(0.0, resolution[layer] / r); + o2::math_utils::bringTo02Pi(alpha); + gloXYZ.SetX(r * std::cos(alpha)); + gloXYZ.SetY(r * std::sin(alpha)); + gloXYZ.SetZ(hitPos.Z() + gRandom->Gaus(0.0, resolution[layer])); + trkXYZ.SetX(r); + trkXYZ.SetY(0.f); + trkXYZ.SetZ(gloXYZ.Z()); + } + this->mMinR[layer] = std::min(this->mMinR[layer], r); + this->mMaxR[layer] = std::max(this->mMaxR[layer], r); + this->addTrackingFrameInfoToLayer(layer, gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), trkXYZ.x(), alpha, + std::array{trkXYZ.y(), trkXYZ.z()}, + std::array{resolution[layer] * resolution[layer], 0., resolution[layer] * resolution[layer]}); + /// Rotate to the global frame + this->addClusterToLayer(layer, gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), this->mUnsortedClusters[layer].size()); + this->addClusterExternalIndexToLayer(layer, hitCounter); + MCCompLabel label{hit.GetTrackID(), static_cast(iEvent), 0}; + labels->addElement(hitCounter, label); + this->mClusterSize[hitCounter] = 1; // For compatibility with cluster-based tracking, set cluster size to 1 for hits + hitCounter++; + } + trkHit->clear(); + + // Update ROF structure when we complete an ROF or reach the last event + if ((iEvent + 1) % inROFpileup == 0 || iEvent == nEvents - 1) { + iRof++; + for (unsigned int iLayer{0}; iLayer < this->mUnsortedClusters.size(); ++iLayer) { + this->mROFramesClusters[iLayer][iRof] = this->mUnsortedClusters[iLayer].size(); // effectively calculating an exclusive sum + } + // Update primary vertices ROF structure + } + this->mClusterLabels = labels; + } + return this->mNrof; +} + +template +void TimeFrame::getPrimaryVerticesFromMC(TTree* mcHeaderTree, int nRofs, Long64_t nEvents, int inROFpileup) +{ + auto mcheader = new o2::dataformats::MCEventHeader; + mcHeaderTree->SetBranchAddress("MCEventHeader.", &mcheader); + + this->mROFramesPV.clear(); + this->mROFramesPV.resize(nRofs + 1, 0); + this->mPrimaryVertices.clear(); + + int iRof{0}; + for (Long64_t iEvent = 0; iEvent < nEvents; ++iEvent) { + mcHeaderTree->GetEntry(iEvent); + o2::its::Vertex vertex; + vertex.setXYZ(mcheader->GetX(), mcheader->GetY(), mcheader->GetZ()); + vertex.setNContributors(30); + vertex.setChi2(0.f); + LOGP(debug, "ROF {}: Added primary vertex at ({}, {}, {})", iRof, mcheader->GetX(), mcheader->GetY(), mcheader->GetZ()); + this->mPrimaryVertices.push_back(vertex); + if ((iEvent + 1) % inROFpileup == 0 || iEvent == nEvents - 1) { + iRof++; + this->mROFramesPV[iRof] = this->mPrimaryVertices.size(); // effectively calculating an exclusive sum + } + } + this->mMultiplicityCutMask.resize(nRofs, true); /// all ROFs are valid with MC primary vertices. +} + +// Explicit template instantiation for TRK with 11 layers +template class TimeFrame<11>; + +} // namespace o2::trk diff --git a/Detectors/Upgrades/ALICE3/TRK/workflow/CMakeLists.txt b/Detectors/Upgrades/ALICE3/TRK/workflow/CMakeLists.txt index e86ed7982c85b..d6c8ea85c2bbd 100644 --- a/Detectors/Upgrades/ALICE3/TRK/workflow/CMakeLists.txt +++ b/Detectors/Upgrades/ALICE3/TRK/workflow/CMakeLists.txt @@ -14,17 +14,23 @@ o2_add_library(TRKWorkflow SOURCES src/DigitReaderSpec.cxx src/DigitWriterSpec.cxx src/TrackerSpec.cxx + src/TrackWriterSpec.cxx src/RecoWorkflow.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::GPUWorkflow O2::SimConfig O2::DataFormatsITSMFT O2::SimulationDataFormat - O2::DPLUtils) + O2::DPLUtils + O2::TRKBase + O2::TRKSimulation + O2::TRKReconstruction + nlohmann_json::nlohmann_json) o2_add_executable(reco-workflow SOURCES src/trk-reco-workflow.cxx COMPONENT_NAME alice3-trk PUBLIC_LINK_LIBRARIES O2::TRKWorkflow O2::TRKSimulation - O2::ITStracking) \ No newline at end of file + O2::TRKReconstruction + O2::ITStracking) diff --git a/Detectors/Upgrades/ALICE3/TRK/workflow/README.md b/Detectors/Upgrades/ALICE3/TRK/workflow/README.md new file mode 100644 index 0000000000000..afb30ed6dbdd3 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/workflow/README.md @@ -0,0 +1,130 @@ +# TRK Reconstruction Workflow + +This document describes how to run the TRK (ALICE 3 Tracker) reconstruction workflow and provides examples of configuration files. + +## Overview + +The TRK reconstruction workflow performs track reconstruction from simulated hits, producing reconstructed tracks with MC truth labels. The workflow currently supports the track reconstruction from hits using the Cellular Automaton (CA) algorithm. The ouput is stored to a ROOT file for offline analysis (example of QA macro provided in `macros/test/CheckTracksCA.C`). + +## Quick Start + +### Basic Command + +```bash +o2-alice3-trk-reco-workflow --tracking-from-hits-config config_tracker.json -b +``` + +### Command Line Options + +- `--tracking-from-hits-config `: Path to tracking configuration JSON file (required) +- `-b`: Batch mode (no GUI) +- `--disable-root-output`: Skip writing tracks to ROOT file +- `--help`: Show all available options + +## Configuration File + +The tracking configuration is provided via a JSON file that specifies: +1. Input file paths +2. Geometry parameters (magnetic field, detector pitch) +3. Tracking algorithm parameters (can specify multiple iterations) + +### Example Configuration (`config_tracker.json`) + +```json +{ + "inputfiles": { + "hits": "o2sim_HitsTRK.root", + "geometry": "o2sim_geometry.root", + "mcHeader": "o2sim_MCHeader.root", + "kinematics": "o2sim_Kine.root" + }, + "geometry": { + "bz": 5.0, + "pitch": [0.001, 0.001, 0.001, 0.001, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004, 0.004] + }, + "trackingparams": [{ + "NLayers": 11, + "DeltaROF": 0, + "LayerZ": [25.1, 25.1, 25.1, 64.2, 64.2, 64.2, 64.2, 64.2, 128.5, 128.5, 128.5], + "LayerRadii": [0.5, 1.2, 2.5, 7.05, 9.05, 12.05, 20.05, 30.05, 45.05, 60.5, 80.05], + "LayerxX0": [0.001, 0.001, 0.001, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01], + "LayerResolution": [0.0003, 0.0003, 0.0003, 0.0003, 0.0012, 0.0012, 0.0012, 0.0012, 0.0012, 0.0012, 0.0012], + "SystErrorY2": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + "SystErrorZ2": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + "ZBins": 256, + "PhiBins": 128, + "nROFsPerIterations": -1, + "UseDiamond": false, + "Diamond": [0.0, 0.0, 0.0], + "AllowSharingFirstCluster": false, + "ClusterSharing": 0, + "MinTrackLength": 7, + "NSigmaCut": 10, + "PVres": 0.01, + "TrackletMinPt": 0.1, + "TrackletsPerClusterLimit": 2.0, + "CellDeltaTanLambdaSigma": 0.007, + "CellsPerClusterLimit": 2.0, + "MaxChi2ClusterAttachment": 60.0, + "MaxChi2NDF": 30.0, + "ReseedIfShorter": 6, + "MinPt": [0.0, 0.0, 0.0, 0.0], + "StartLayerMask": 4095, + "RepeatRefitOut": false, + "ShiftRefToCluster": true, + "FindShortTracks": false, + "PerPrimaryVertexProcessing": false, + "SaveTimeBenchmarks": false, + "DoUPCIteration": false, + "FataliseUponFailure": true, + "UseTrackFollower": true, + "UseTrackFollowerTop": false, + "UseTrackFollowerBot": false, + "UseTrackFollowerMix": true, + "TrackFollowerNSigmaCutZ": 1.0, + "TrackFollowerNSigmaCutPhi": 1.0, + "createArtefactLabels": false, + "PrintMemory": false, + "DropTFUponFailure": false + }] +} +``` +Note that the `trackingparams` field can contain multiple sets of parameters for different iterations of the tracking algorithm. The example above shows a single iteration with 11 layers and it is **not** optimized. + +## Complete Workflow Example + +### 1. Run Simulation + +First, generate simulation data: + +```bash +o2-sim-serial-run5 -n 200 -g pythia8hi -m TRK --configKeyValues "Diamond.width[0]=0.01;Diamond.width[1]=0.01;Diamond.width[2]=5;TRKBase.layoutML=kTurboStaves;TRKBase.layoutOL=kStaggered;" +``` + +This produces, among other files: +- `o2sim_HitsTRK.root` +- `o2sim_geometry.root` +- `o2sim_MCHeader.root` +- `o2sim_Kine.root` +That will be used by the reconstruction as currently we do not have clusters. + +### 2. Run Reconstruction + +Execute the tracking workflow: + +```bash +o2-alice3-trk-reco-workflow --tracking-from-hits-config config_tracker.json -b +``` + +This produces: +- `o2trac_trk.root`: Reconstructed tracks with MC labels + +### 3. Run Quality Assurance + +Analyze the tracking performance: + +```bash +root -l +.L CheckTracksCA.C+ +CheckTracksCA("o2trac_trk.root", "o2sim_Kine.root", "o2sim_HitsTRK.root", "trk_qa_output.root") +``` diff --git a/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/RecoWorkflow.h b/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/RecoWorkflow.h index 98d4154f11dd8..7046955a20c2e 100644 --- a/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/RecoWorkflow.h +++ b/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/RecoWorkflow.h @@ -14,6 +14,7 @@ #include "Framework/WorkflowSpec.h" #include "GPUDataTypesConfig.h" +#include namespace o2::trk { @@ -21,6 +22,7 @@ namespace reco_workflow { o2::framework::WorkflowSpec getWorkflow(bool useMC, + const std::string& hitRecoConfig, bool upstreamDigits = false, bool upstreamClusters = false, bool disableRootOutput = false, diff --git a/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/TrackWriterSpec.h b/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/TrackWriterSpec.h new file mode 100644 index 0000000000000..105504e7c9fe6 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/TrackWriterSpec.h @@ -0,0 +1,31 @@ +// 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 TrackWriterSpec.h + +#ifndef O2_TRK_TRACKWRITER +#define O2_TRK_TRACKWRITER + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace trk +{ + +/// create a processor spec +/// write TRK tracks to ROOT file +o2::framework::DataProcessorSpec getTrackWriterSpec(bool useMC); + +} // namespace trk +} // namespace o2 + +#endif /* O2_TRK_TRACKWRITER */ diff --git a/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/TrackerSpec.h b/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/TrackerSpec.h index dac1826e21cf6..33b25737bbc29 100644 --- a/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/TrackerSpec.h +++ b/Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/TrackerSpec.h @@ -19,6 +19,9 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" +#include + +#include "ITStracking/BoundedAllocator.h" #include "ITStracking/TrackingInterface.h" #include "GPUDataTypesConfig.h" @@ -26,6 +29,8 @@ #include "TStopwatch.h" +#include + namespace o2::trk { class TrackerDPL : public framework::Task @@ -33,6 +38,7 @@ class TrackerDPL : public framework::Task public: TrackerDPL(std::shared_ptr gr, bool isMC, + const std::string& hitRecoConfig, gpu::gpudatatypes::DeviceType dType = gpu::gpudatatypes::DeviceType::CPU); ~TrackerDPL() override = default; void init(framework::InitContext& ic) final; @@ -43,14 +49,18 @@ class TrackerDPL : public framework::Task private: void updateTimeDependentParams(framework::ProcessingContext& pc); + std::vector createTrackingParamsFromConfig(); // std::unique_ptr mRecChain = nullptr; // std::unique_ptr mChainITS = nullptr; // std::shared_ptr mGGCCDBRequest; // ITSTrackingInterface mITSTrackingInterface; + std::shared_ptr mMemoryPool; + std::shared_ptr mTaskArena; + nlohmann::json mHitRecoConfig; TStopwatch mTimer; }; -framework::DataProcessorSpec getTrackerSpec(bool useMC, gpu::gpudatatypes::DeviceType dType = gpu::gpudatatypes::DeviceType::CPU); +framework::DataProcessorSpec getTrackerSpec(bool useMC, const std::string& hitRecoConfig, gpu::gpudatatypes::DeviceType dType = gpu::gpudatatypes::DeviceType::CPU); } // namespace o2::trk #endif /* O2_TRK_TRACKERDPL */ diff --git a/Detectors/Upgrades/ALICE3/TRK/workflow/src/RecoWorkflow.cxx b/Detectors/Upgrades/ALICE3/TRK/workflow/src/RecoWorkflow.cxx index 09d447a576e48..5f6cbe2f96b04 100644 --- a/Detectors/Upgrades/ALICE3/TRK/workflow/src/RecoWorkflow.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/workflow/src/RecoWorkflow.cxx @@ -11,12 +11,16 @@ #include "TRKWorkflow/RecoWorkflow.h" #include "TRKWorkflow/TrackerSpec.h" +#include "TRKWorkflow/TrackWriterSpec.h" #include "Framework/CCDBParamSpec.h" +#include + namespace o2::trk::reco_workflow { framework::WorkflowSpec getWorkflow(bool useMC, + const std::string& hitRecoConfig, bool upstreamDigits, bool upstreamClusters, bool disableRootOutput, @@ -24,7 +28,12 @@ framework::WorkflowSpec getWorkflow(bool useMC, o2::gpu::gpudatatypes::DeviceType dtype) { framework::WorkflowSpec specs; - specs.emplace_back(o2::trk::getTrackerSpec(useMC, dtype)); + specs.emplace_back(o2::trk::getTrackerSpec(useMC, hitRecoConfig, dtype)); + + if (!disableRootOutput) { + specs.emplace_back(o2::trk::getTrackWriterSpec(useMC)); + } + return specs; } diff --git a/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackWriterSpec.cxx b/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackWriterSpec.cxx new file mode 100644 index 0000000000000..1606c32a0ea78 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackWriterSpec.cxx @@ -0,0 +1,57 @@ +// 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 TrackWriterSpec.cxx + +#include + +#include "TRKWorkflow/TrackWriterSpec.h" +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "DataFormatsITS/TrackITS.h" +#include "SimulationDataFormat/MCCompLabel.h" + +using namespace o2::framework; + +namespace o2 +{ +namespace trk +{ + +template +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition; +using LabelsType = std::vector; +using namespace o2::header; + +DataProcessorSpec getTrackWriterSpec(bool useMC) +{ + // Spectators for logging + auto tracksSize = std::make_shared(0); + auto tracksSizeGetter = [tracksSize](std::vector const& tracks) { + *tracksSize = tracks.size(); + }; + auto logger = [tracksSize]() { + LOG(info) << "TRKTrackWriter pulled " << *tracksSize << " tracks"; + }; + + return MakeRootTreeWriterSpec("trk-track-writer", + "o2trac_trk.root", + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree with TRK tracks"}, + BranchDefinition>{InputSpec{"tracks", "TRK", "TRACKS", 0}, + "TRKTrack", + tracksSizeGetter}, + BranchDefinition{InputSpec{"labels", "TRK", "TRACKSMCTR", 0}, + "TRKTrackMCTruth", + (useMC ? 1 : 0), // one branch if mc labels enabled + ""})(); +} + +} // namespace trk +} // namespace o2 diff --git a/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx b/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx index 868a8acc0fc6e..8f26478f4496e 100644 --- a/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx @@ -11,10 +11,24 @@ #include +#include "DetectorsBase/GeometryManager.h" +#include "ITStracking/TimeFrame.h" +#include "ITStracking/Configuration.h" +#include "Field/MagneticField.h" #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/CCDBParamSpec.h" +#include "SimulationDataFormat/MCEventHeader.h" +#include "SimulationDataFormat/MCCompLabel.h" +#include "TRKBase/GeometryTGeo.h" +#include "TRKBase/SegmentationChip.h" +#include "TRKSimulation/Hit.h" +#include "TRKReconstruction/TimeFrame.h" #include "TRKWorkflow/TrackerSpec.h" +#include + +#include +#include namespace o2 { @@ -25,8 +39,14 @@ using Vertex = o2::dataformats::Vertex>; TrackerDPL::TrackerDPL(std::shared_ptr gr, bool isMC, + const std::string& hitRecoConfigFileName, o2::gpu::gpudatatypes::DeviceType dType) { + if (!hitRecoConfigFileName.empty()) { + std::ifstream configFile(hitRecoConfigFileName); + mHitRecoConfig = nlohmann::json::parse(configFile); + } + // mITSTrackingInterface.setTrackingMode(trMode); } @@ -46,13 +66,288 @@ void TrackerDPL::stop() LOGF(info, "CPU Reconstruction total timing: Cpu: %.3e Real: %.3e s in %d slots", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } +std::vector TrackerDPL::createTrackingParamsFromConfig() +{ + std::vector trackingParams; + + if (!mHitRecoConfig.contains("trackingparams") || !mHitRecoConfig["trackingparams"].is_array()) { + LOGP(fatal, "No trackingparams field found in configuration or it is not an array. Returning empty vector."); + return trackingParams; + } + + for (const auto& paramConfig : mHitRecoConfig["trackingparams"]) { + o2::its::TrackingParameters params; + + // Parse integer parameters + if (paramConfig.contains("NLayers")) { + params.NLayers = paramConfig["NLayers"].get(); + } + if (paramConfig.contains("DeltaROF")) { + params.DeltaROF = paramConfig["DeltaROF"].get(); + } + if (paramConfig.contains("ZBins")) { + params.ZBins = paramConfig["ZBins"].get(); + } + if (paramConfig.contains("PhiBins")) { + params.PhiBins = paramConfig["PhiBins"].get(); + } + if (paramConfig.contains("nROFsPerIterations")) { + params.nROFsPerIterations = paramConfig["nROFsPerIterations"].get(); + } + if (paramConfig.contains("ClusterSharing")) { + params.ClusterSharing = paramConfig["ClusterSharing"].get(); + } + if (paramConfig.contains("MinTrackLength")) { + params.MinTrackLength = paramConfig["MinTrackLength"].get(); + } + if (paramConfig.contains("ReseedIfShorter")) { + params.ReseedIfShorter = paramConfig["ReseedIfShorter"].get(); + } + if (paramConfig.contains("StartLayerMask")) { + params.StartLayerMask = paramConfig["StartLayerMask"].get(); + } + + // Parse float parameters + if (paramConfig.contains("NSigmaCut")) { + params.NSigmaCut = paramConfig["NSigmaCut"].get(); + } + if (paramConfig.contains("PVres")) { + params.PVres = paramConfig["PVres"].get(); + } + if (paramConfig.contains("TrackletMinPt")) { + params.TrackletMinPt = paramConfig["TrackletMinPt"].get(); + } + if (paramConfig.contains("TrackletsPerClusterLimit")) { + params.TrackletsPerClusterLimit = paramConfig["TrackletsPerClusterLimit"].get(); + } + if (paramConfig.contains("CellDeltaTanLambdaSigma")) { + params.CellDeltaTanLambdaSigma = paramConfig["CellDeltaTanLambdaSigma"].get(); + } + if (paramConfig.contains("CellsPerClusterLimit")) { + params.CellsPerClusterLimit = paramConfig["CellsPerClusterLimit"].get(); + } + if (paramConfig.contains("MaxChi2ClusterAttachment")) { + params.MaxChi2ClusterAttachment = paramConfig["MaxChi2ClusterAttachment"].get(); + } + if (paramConfig.contains("MaxChi2NDF")) { + params.MaxChi2NDF = paramConfig["MaxChi2NDF"].get(); + } + if (paramConfig.contains("TrackFollowerNSigmaCutZ")) { + params.TrackFollowerNSigmaCutZ = paramConfig["TrackFollowerNSigmaCutZ"].get(); + } + if (paramConfig.contains("TrackFollowerNSigmaCutPhi")) { + params.TrackFollowerNSigmaCutPhi = paramConfig["TrackFollowerNSigmaCutPhi"].get(); + } + + // Parse boolean parameters + if (paramConfig.contains("UseDiamond")) { + params.UseDiamond = paramConfig["UseDiamond"].get(); + } + if (paramConfig.contains("AllowSharingFirstCluster")) { + params.AllowSharingFirstCluster = paramConfig["AllowSharingFirstCluster"].get(); + } + if (paramConfig.contains("RepeatRefitOut")) { + params.RepeatRefitOut = paramConfig["RepeatRefitOut"].get(); + } + if (paramConfig.contains("ShiftRefToCluster")) { + params.ShiftRefToCluster = paramConfig["ShiftRefToCluster"].get(); + } + if (paramConfig.contains("FindShortTracks")) { + params.FindShortTracks = paramConfig["FindShortTracks"].get(); + } + if (paramConfig.contains("PerPrimaryVertexProcessing")) { + params.PerPrimaryVertexProcessing = paramConfig["PerPrimaryVertexProcessing"].get(); + } + if (paramConfig.contains("SaveTimeBenchmarks")) { + params.SaveTimeBenchmarks = paramConfig["SaveTimeBenchmarks"].get(); + } + if (paramConfig.contains("DoUPCIteration")) { + params.DoUPCIteration = paramConfig["DoUPCIteration"].get(); + } + if (paramConfig.contains("FataliseUponFailure")) { + params.FataliseUponFailure = paramConfig["FataliseUponFailure"].get(); + } + if (paramConfig.contains("UseTrackFollower")) { + params.UseTrackFollower = paramConfig["UseTrackFollower"].get(); + } + if (paramConfig.contains("UseTrackFollowerTop")) { + params.UseTrackFollowerTop = paramConfig["UseTrackFollowerTop"].get(); + } + if (paramConfig.contains("UseTrackFollowerBot")) { + params.UseTrackFollowerBot = paramConfig["UseTrackFollowerBot"].get(); + } + if (paramConfig.contains("UseTrackFollowerMix")) { + params.UseTrackFollowerMix = paramConfig["UseTrackFollowerMix"].get(); + } + if (paramConfig.contains("createArtefactLabels")) { + params.createArtefactLabels = paramConfig["createArtefactLabels"].get(); + } + if (paramConfig.contains("PrintMemory")) { + params.PrintMemory = paramConfig["PrintMemory"].get(); + } + if (paramConfig.contains("DropTFUponFailure")) { + params.DropTFUponFailure = paramConfig["DropTFUponFailure"].get(); + } + + // Parse vector parameters + if (paramConfig.contains("LayerZ")) { + params.LayerZ = paramConfig["LayerZ"].get>(); + } + if (paramConfig.contains("LayerRadii")) { + params.LayerRadii = paramConfig["LayerRadii"].get>(); + } + if (paramConfig.contains("LayerxX0")) { + params.LayerxX0 = paramConfig["LayerxX0"].get>(); + } + if (paramConfig.contains("LayerResolution")) { + params.LayerResolution = paramConfig["LayerResolution"].get>(); + } + if (paramConfig.contains("SystErrorY2")) { + params.SystErrorY2 = paramConfig["SystErrorY2"].get>(); + } + if (paramConfig.contains("SystErrorZ2")) { + params.SystErrorZ2 = paramConfig["SystErrorZ2"].get>(); + } + if (paramConfig.contains("MinPt")) { + params.MinPt = paramConfig["MinPt"].get>(); + } + + // Parse Diamond array + if (paramConfig.contains("Diamond") && paramConfig["Diamond"].is_array() && paramConfig["Diamond"].size() == 3) { + params.Diamond[0] = paramConfig["Diamond"][0].get(); + params.Diamond[1] = paramConfig["Diamond"][1].get(); + params.Diamond[2] = paramConfig["Diamond"][2].get(); + } + + // Parse size_t parameter + if (paramConfig.contains("MaxMemory")) { + params.MaxMemory = paramConfig["MaxMemory"].get(); + } + + // Parse CorrType enum + if (paramConfig.contains("CorrType")) { + int corrTypeInt = paramConfig["CorrType"].get(); + params.CorrType = static_cast::MatCorrType>(corrTypeInt); + } + + trackingParams.push_back(params); + } + + LOGP(info, "Loaded {} tracking parameter sets from configuration", trackingParams.size()); + return trackingParams; +} + void TrackerDPL::run(ProcessingContext& pc) { auto cput = mTimer.CpuTime(); auto realt = mTimer.RealTime(); mTimer.Start(false); - // mITSTrackingInterface.updateTimeDependentParams(pc); - // mITSTrackingInterface.run(pc); + + if (!mHitRecoConfig.empty()) { + TFile hitsFile(mHitRecoConfig["inputfiles"]["hits"].get().c_str(), "READ"); + TFile mcHeaderFile(mHitRecoConfig["inputfiles"]["mcHeader"].get().c_str(), "READ"); + TTree* hitsTree = hitsFile.Get("o2sim"); + std::vector* trkHit = nullptr; + hitsTree->SetBranchAddress("TRKHit", &trkHit); + + TTree* mcHeaderTree = mcHeaderFile.Get("o2sim"); + auto mcheader = new o2::dataformats::MCEventHeader; + mcHeaderTree->SetBranchAddress("MCEventHeader.", &mcheader); + + o2::base::GeometryManager::loadGeometry(mHitRecoConfig["inputfiles"]["geometry"].get().c_str(), false, true); + auto* gman = o2::trk::GeometryTGeo::Instance(); + + const Long64_t nEvents{hitsTree->GetEntries()}; + LOGP(info, "Starting reconstruction from hits for {} events", nEvents); + + if (mMemoryPool.get() == nullptr) { + mMemoryPool = std::make_shared(); + } + if (mTaskArena.get() == nullptr) { + mTaskArena = std::make_shared(1); /// TODO: make it configurable + } + + o2::trk::TimeFrame<11> timeFrame; + o2::its::TrackerTraits<11> itsTrackerTraits; + o2::its::Tracker<11> itsTracker(&itsTrackerTraits); + timeFrame.setMemoryPool(mMemoryPool); + itsTrackerTraits.setMemoryPool(mMemoryPool); + itsTrackerTraits.setNThreads(mTaskArena->max_concurrency(), mTaskArena); + itsTrackerTraits.adoptTimeFrame(static_cast*>(&timeFrame)); + itsTracker.adoptTimeFrame(timeFrame); + itsTrackerTraits.setBz(mHitRecoConfig["geometry"]["bz"].get()); + auto field = o2::field::MagneticField::createNominalField(std::round(mHitRecoConfig["geometry"]["bz"].get()), true); + TGeoGlobalMagField::Instance()->SetField(field); + TGeoGlobalMagField::Instance()->Lock(); + + int nRofs = timeFrame.loadROFsFromHitTree(hitsTree, gman, mHitRecoConfig); + + const int inROFpileup{mHitRecoConfig.contains("inROFpileup") ? mHitRecoConfig["inROFpileup"].get() : 1}; + + // Add primary vertices from MC headers for each ROF + timeFrame.getPrimaryVerticesFromMC(mcHeaderTree, nRofs, nEvents, inROFpileup); + // Create tracking parameters from config and set them in the time frame + auto trackingParams = createTrackingParamsFromConfig(); + + itsTrackerTraits.updateTrackingParameters(trackingParams); + + for (size_t iter{0}; iter < trackingParams.size(); ++iter) { + LOGP(info, "{}", trackingParams[iter].asString()); + timeFrame.initialise(iter, trackingParams[iter], 11, false); + itsTrackerTraits.computeLayerTracklets(iter, -1, -1); + LOGP(info, "Number of tracklets in iteration {}: {}", iter, timeFrame.getNumberOfTracklets()); + itsTrackerTraits.computeLayerCells(iter); + LOGP(info, "Number of cells in iteration {}: {}", iter, timeFrame.getNumberOfCells()); + itsTrackerTraits.findCellsNeighbours(iter); + LOGP(info, "Number of cell neighbours in iteration {}: {}", iter, timeFrame.getNumberOfNeighbours()); + itsTrackerTraits.findRoads(iter); + LOGP(info, "Number of roads in iteration {}: {}", iter, timeFrame.getNumberOfTracks()); + itsTrackerTraits.extendTracks(iter); + } + + itsTracker.computeTracksMClabels(); + + // Stream tracks and their MC labels to the output + // Collect all tracks and labels from all ROFs + std::vector allTracks; + std::vector allLabels; + + int totalTracks = 0; + int goodTracks = 0; + int fakeTracks = 0; + + for (int iRof = 0; iRof < nRofs; ++iRof) { + const auto& rofTracks = timeFrame.getTracks(iRof); + const auto& rofLabels = timeFrame.getTracksLabel(iRof); + + allTracks.insert(allTracks.end(), rofTracks.begin(), rofTracks.end()); + allLabels.insert(allLabels.end(), rofLabels.begin(), rofLabels.end()); + + totalTracks += rofTracks.size(); + for (const auto& label : rofLabels) { + if (label.isFake()) { + fakeTracks++; + } else { + goodTracks++; + } + } + } + + LOGP(info, "=== Tracking Summary ==="); + LOGP(info, "Total tracks reconstructed: {}", totalTracks); + LOGP(info, "Good tracks: {} ({:.1f}%)", goodTracks, totalTracks > 0 ? 100.0 * goodTracks / totalTracks : 0); + LOGP(info, "Fake tracks: {} ({:.1f}%)", fakeTracks, totalTracks > 0 ? 100.0 * fakeTracks / totalTracks : 0); + + // Stream tracks and labels to DPL output + pc.outputs().snapshot(o2::framework::Output{"TRK", "TRACKS", 0}, allTracks); + pc.outputs().snapshot(o2::framework::Output{"TRK", "TRACKSMCTR", 0}, allLabels); + + LOGP(info, "Tracks and MC labels streamed to output"); + + pc.services().get().endOfStream(); + pc.services().get().readyToQuit(framework::QuitRequest::Me); + } + mTimer.Stop(); LOGP(info, "CPU Reconstruction time for this TF {} s (cpu), {} s (wall)", mTimer.CpuTime() - cput, mTimer.RealTime() - realt); } @@ -67,16 +362,11 @@ void TrackerDPL::endOfStream(EndOfStreamContext& ec) LOGF(info, "TRK CA-Tracker total timing: Cpu: %.3e Real: %.3e s in %d slots", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getTrackerSpec(bool useMC, o2::gpu::gpudatatypes::DeviceType dType) +DataProcessorSpec getTrackerSpec(bool useMC, const std::string& hitRecoConfig, o2::gpu::gpudatatypes::DeviceType dType) { std::vector inputs; - - // inputs.emplace_back("compClusters", "TRK", "COMPCLUSTERS", 0, Lifetime::Timeframe); - // inputs.emplace_back("patterns", "TRK", "PATTERNS", 0, Lifetime::Timeframe); - // inputs.emplace_back("ROframes", "TRK", "CLUSTERSROF", 0, Lifetime::Timeframe); - - // inputs.emplace_back("itscldict", "TRK", "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec("ITS/Calib/ClusterDictionary")); - // inputs.emplace_back("itsalppar", "TRK", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/AlpideParam")); + std::vector outputs; + outputs.emplace_back("TRK", "TRACKS", 0, Lifetime::Timeframe); auto ggRequest = std::make_shared(false, // orbitResetTime false, // GRPECS=true false, // GRPLHCIF @@ -85,8 +375,29 @@ DataProcessorSpec getTrackerSpec(bool useMC, o2::gpu::gpudatatypes::DeviceType d o2::base::GRPGeomRequest::None, // geometry, but ignored until it will be put in the CCDB inputs, true); - std::vector outputs; - outputs.emplace_back("TRK", "TRACKS", 0, Lifetime::Timeframe); + + if (!hitRecoConfig.empty()) { + outputs.emplace_back("TRK", "TRACKSMCTR", 0, Lifetime::Timeframe); + return DataProcessorSpec{ + "trk-hits-tracker", + {}, + outputs, + AlgorithmSpec{adaptFromTask(ggRequest, + useMC, + hitRecoConfig, + dType)}, + Options{ConfigParamSpec{"max-loops", VariantType::Int, 1, {"max number of loops"}}}}; + } + + inputs.emplace_back("dummy", "TRK", "DUMMY", 0, Lifetime::Timeframe); + + // inputs.emplace_back("compClusters", "TRK", "COMPCLUSTERS", 0, Lifetime::Timeframe); + // inputs.emplace_back("patterns", "TRK", "PATTERNS", 0, Lifetime::Timeframe); + // inputs.emplace_back("ROframes", "TRK", "CLUSTERSROF", 0, Lifetime::Timeframe); + + // inputs.emplace_back("itscldict", "TRK", "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec("ITS/Calib/ClusterDictionary")); + // inputs.emplace_back("itsalppar", "TRK", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/AlpideParam")); + // outputs.emplace_back("TRK", "TRACKCLSID", 0, Lifetime::Timeframe); // outputs.emplace_back("TRK", "TRKTrackROF", 0, Lifetime::Timeframe); // outputs.emplace_back("TRK", "VERTICES", 0, Lifetime::Timeframe); @@ -108,6 +419,7 @@ DataProcessorSpec getTrackerSpec(bool useMC, o2::gpu::gpudatatypes::DeviceType d outputs, AlgorithmSpec{adaptFromTask(ggRequest, useMC, + hitRecoConfig, dType)}, Options{}}; } diff --git a/Detectors/Upgrades/ALICE3/TRK/workflow/src/trk-reco-workflow.cxx b/Detectors/Upgrades/ALICE3/TRK/workflow/src/trk-reco-workflow.cxx index 8f44b01da1c9c..166e6f65b4b2b 100644 --- a/Detectors/Upgrades/ALICE3/TRK/workflow/src/trk-reco-workflow.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/workflow/src/trk-reco-workflow.cxx @@ -52,6 +52,7 @@ void customize(std::vector& workflowOptions) {"clusters-from-upstream", VariantType::Bool, false, {"clusters will be provided from upstream, skip clusterizer"}}, {"disable-root-output", VariantType::Bool, false, {"do not write output root files"}}, {"disable-mc", VariantType::Bool, false, {"disable MC propagation even if available"}}, + {"tracking-from-hits-config", VariantType::String, "", {"JSON file with tracking from hits configuration"}}, {"disable-tracking", VariantType::Bool, false, {"disable tracking step"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, {"use-gpu-workflow", VariantType::Bool, false, {"use GPU workflow (default: false)"}}, @@ -66,6 +67,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) { // Update the (declared) parameters if changed from the command line auto useMC = !configcontext.options().get("disable-mc"); + auto hitRecoConfig = configcontext.options().get("tracking-from-hits-config"); auto useGpuWF = configcontext.options().get("use-gpu-workflow"); auto gpuDevice = static_cast(configcontext.options().get("gpu-device")); auto extDigits = configcontext.options().get("digits-from-upstream"); @@ -76,5 +78,5 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // write the configuration used for the reco workflow o2::conf::ConfigurableParam::writeINI("o2itsrecoflow_configuration.ini"); - return o2::trk::reco_workflow::getWorkflow(useMC, extDigits, extClusters, disableRootOutput, useGpuWF, gpuDevice); + return o2::trk::reco_workflow::getWorkflow(useMC, hitRecoConfig, extDigits, extClusters, disableRootOutput, useGpuWF, gpuDevice); } From 712170392332bf82ef808d71c26d6a805b8e675f Mon Sep 17 00:00:00 2001 From: Anton Alkin Date: Tue, 17 Feb 2026 14:47:47 +0100 Subject: [PATCH 209/234] DPL Analysis: cleanup AnalysisTask.h and ASoA.h (#15008) --- Framework/Core/include/Framework/ASoA.h | 62 +++---- .../Core/include/Framework/AnalysisManagers.h | 6 - .../Core/include/Framework/AnalysisTask.h | 163 +++++++++--------- .../Core/include/Framework/Configurable.h | 15 +- Framework/Core/test/test_Concepts.cxx | 1 + .../include/Framework/StructToTuple.h | 46 ++--- 6 files changed, 136 insertions(+), 157 deletions(-) diff --git a/Framework/Core/include/Framework/ASoA.h b/Framework/Core/include/Framework/ASoA.h index 4fd35e0dc5065..7586d6a6d3c63 100644 --- a/Framework/Core/include/Framework/ASoA.h +++ b/Framework/Core/include/Framework/ASoA.h @@ -405,15 +405,15 @@ class Table; /// Type-checking index column binding struct Binding { void const* ptr = nullptr; - size_t hash = 0; - std::span refs; + uint32_t hash = 0; + // std::span refs; template void bind(T const* table) { ptr = table; hash = o2::framework::TypeIdHelpers::uniqueId(); - refs = std::span{T::originals}; + // refs = std::span{T::originals}; } template @@ -1293,6 +1293,9 @@ struct ArrowHelpers { template concept is_iterator = framework::base_of_template || framework::specialization_of_template; +template +concept is_table_or_iterator = is_table || is_iterator; + template concept with_originals = requires { T::originals.size(); @@ -2724,7 +2727,7 @@ consteval auto getIndexTargets() return !(*mColumnIterator).empty(); \ } \ \ - template \ + template \ auto _Getter_##_as() const \ { \ if (O2_BUILTIN_UNLIKELY(mBinding.ptr == nullptr)) { \ @@ -2734,10 +2737,15 @@ consteval auto getIndexTargets() if (O2_BUILTIN_UNLIKELY(t == nullptr)) { \ o2::soa::dereferenceWithWrongType(#_Getter_, #_Table_); \ } \ - return getIterators(); \ + auto result = std::vector(); \ + result.reserve((*mColumnIterator).size()); \ + for (auto& i : *mColumnIterator) { \ + result.emplace_back(t->rawIteratorAt(i)); \ + } \ + return result; \ } \ \ - template \ + template \ auto filtered_##_Getter_##_as() const \ { \ if (O2_BUILTIN_UNLIKELY(mBinding.ptr == nullptr)) { \ @@ -2747,35 +2755,15 @@ consteval auto getIndexTargets() if (O2_BUILTIN_UNLIKELY(t == nullptr)) { \ o2::soa::dereferenceWithWrongType(#_Getter_, #_Table_); \ } \ - return getFilteredIterators(); \ - } \ - \ - template \ - auto getIterators() const \ - { \ - auto result = std::vector(); \ - for (auto& i : *mColumnIterator) { \ - result.push_back(mBinding.get()->rawIteratorAt(i)); \ - } \ - return result; \ - } \ - \ - template \ - std::vector getFilteredIterators() const \ - { \ - if constexpr (o2::soa::is_filtered_table) { \ - auto result = std::vector(); \ - for (auto const& i : *mColumnIterator) { \ - auto pos = mBinding.get()->isInSelectedRows(i); \ - if (pos > 0) { \ - result.emplace_back(mBinding.get()->iteratorAt(pos)); \ - } \ + auto result = std::vector(); \ + result.reserve((*mColumnIterator).size()); \ + for (auto const& i : *mColumnIterator) { \ + auto pos = t->isInSelectedRows(i); \ + if (pos > 0) { \ + result.emplace_back(t->iteratorAt(pos)); \ } \ - return result; \ - } else { \ - static_assert(o2::framework::always_static_assert_v, "T is not a Filtered type"); \ } \ - return {}; \ + return result; \ } \ \ auto _Getter_() const \ @@ -3090,15 +3078,9 @@ consteval auto getIndexTargets() if (O2_BUILTIN_UNLIKELY(t == nullptr)) { \ o2::soa::dereferenceWithWrongType(#_Getter_, "self"); \ } \ - return getIterators(); \ - } \ - \ - template \ - auto getIterators() const \ - { \ auto result = std::vector(); \ for (auto& i : *mColumnIterator) { \ - result.push_back(mBinding.get()->rawIteratorAt(i)); \ + result.push_back(t->rawIteratorAt(i)); \ } \ return result; \ } \ diff --git a/Framework/Core/include/Framework/AnalysisManagers.h b/Framework/Core/include/Framework/AnalysisManagers.h index fd41a079c6570..121ce7f4b4a77 100644 --- a/Framework/Core/include/Framework/AnalysisManagers.h +++ b/Framework/Core/include/Framework/AnalysisManagers.h @@ -534,12 +534,6 @@ void bindExternalIndicesPartition(P& partition, T*... tables) } /// Cache handling -template -bool preInitializeCache(InitContext&, T&) -{ - return false; -} - template bool initializeCache(ProcessingContext&, T&) { diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index eb98d55cc24b2..fbd523c7b0c37 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -22,7 +22,6 @@ #include "Framework/EndOfStreamContext.h" #include "Framework/GroupSlicer.h" #include "Framework/StructToTuple.h" -#include "Framework/Traits.h" #include "Framework/TypeIdHelpers.h" #include "Framework/ArrowTableSlicingCache.h" #include "Framework/AnalysisDataModel.h" @@ -66,17 +65,20 @@ static constexpr bool is_enumeration_v> = true; template concept is_enumeration = is_enumeration_v>; +template +concept is_table_iterator_or_enumeration = soa::is_table_or_iterator || is_enumeration; + // Helper struct which builds a DataProcessorSpec from // the contents of an AnalysisTask... namespace { struct AnalysisDataProcessorBuilder { - template + template static void addGroupingCandidates(Cache& bk, Cache& bku, bool enabled) { - [&bk, &bku, enabled](framework::pack) mutable { + [](framework::pack, Cache& bk, Cache& bku, bool enabled) { auto key = std::string{"fIndex"} + o2::framework::cutString(soa::getLabelFromType>()); - ([&bk, &bku, &key, enabled]() mutable { + ([](Cache& bk, Cache& bku, bool enabled, std::string const& key) { if constexpr (soa::relatedByIndex, std::decay_t>()) { Entry e{soa::getLabelFromTypeForKey>(key), soa::getMatcherFromTypeForKey>(key), key, enabled}; if constexpr (o2::soa::is_smallgroups>) { @@ -85,9 +87,9 @@ struct AnalysisDataProcessorBuilder { framework::updatePairList(bk, e); } } - }(), + }(bk, bku, enabled, key), ...); - }(framework::pack{}); + }(framework::pack{}, bk, bku, enabled); } template @@ -171,8 +173,8 @@ struct AnalysisDataProcessorBuilder { return true; } /// 1. enumeration (must be the only argument) - template - static void inputsFromArgs(R (C::*)(A), const char* /*name*/, bool /*value*/, std::vector& inputs, std::vector&) //, Cache&, Cache&) + template + static void inputsFromArgs(void (C::*)(A), const char* /*name*/, bool /*value*/, std::vector& inputs, std::vector&) //, Cache&, Cache&) { std::vector inputMetadata; // FIXME: for the moment we do not support begin, end and step. @@ -180,37 +182,37 @@ struct AnalysisDataProcessorBuilder { } /// 2. 1st argument is an iterator - template - static void inputsFromArgs(R (C::*)(A, Args...), const char* name, bool value, std::vector& inputs, std::vector& eInfos) //, Cache& bk, Cache& bku) + template + static void inputsFromArgs(void (C::*)(A, Args...), const char* name, bool value, std::vector& inputs, std::vector& eInfos) //, Cache& bk, Cache& bku) requires(std::is_lvalue_reference_v && (std::is_lvalue_reference_v && ...)) { - constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); + constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); addInputsAndExpressions::parent_t, Args...>(hash, name, value, inputs, eInfos); } /// 3. generic case - template - static void inputsFromArgs(R (C::*)(Args...), const char* name, bool value, std::vector& inputs, std::vector& eInfos) //, Cache&, Cache&) + template + static void inputsFromArgs(void (C::*)(Args...), const char* name, bool value, std::vector& inputs, std::vector& eInfos) //, Cache&, Cache&) requires(std::is_lvalue_reference_v && ...) { - constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); + constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); addInputsAndExpressions(hash, name, value, inputs, eInfos); } /// 1. enumeration (no grouping) - template - static void cacheFromArgs(R (C::*)(A), bool, Cache&, Cache&) + template + static void cacheFromArgs(void (C::*)(A), bool, Cache&, Cache&) { } /// 2. iterator (the only grouping case) - template - static void cacheFromArgs(R (C::*)(A, Args...), bool value, Cache& bk, Cache& bku) + template + static void cacheFromArgs(void (C::*)(A, Args...), bool value, Cache& bk, Cache& bku) { addGroupingCandidates(bk, bku, value); } /// 3. generic case (no grouping) - template - static void cacheFromArgs(R (C::*)(A, Args...), bool, Cache&, Cache&) + template + static void cacheFromArgs(void (C::*)(A, Args...), bool, Cache&, Cache&) { } @@ -285,51 +287,53 @@ struct AnalysisDataProcessorBuilder { } } - template - static auto bindGroupingTable(InputRecord& record, R (C::*)(Grouping, Args...), std::vector& infos) + template + static auto bindGroupingTable(InputRecord& record, void (C::*)(Grouping, Args...), std::vector& infos) requires(!std::same_as) { - constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); + constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); return extract, 0>(record, infos, hash); } - template - static auto bindAssociatedTables(InputRecord& record, R (C::*)(Grouping, Args...), std::vector& infos) + template + static auto bindAssociatedTables(InputRecord& record, void (C::*)(Grouping, Args...), std::vector& infos) requires(!std::same_as && sizeof...(Args) > 0) { constexpr auto p = pack{}; - constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); + constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); return std::make_tuple(extract, has_type_at_v(p) + 1>(record, infos, hash)...); } - template + template static void overwriteInternalIndices(std::tuple& dest, std::tuple const& src) { (std::get(dest).bindInternalIndicesTo(&std::get(src)), ...); } - template - static void invokeProcess(Task& task, InputRecord& inputs, R (C::*processingFunction)(Grouping, Associated...), std::vector& infos, ArrowTableSlicingCache& slices) + template + static void invokeProcess(Task& task, InputRecord& inputs, void (Task::*processingFunction)(Grouping, Associated...), std::vector& infos, ArrowTableSlicingCache& slices) { using G = std::decay_t; auto groupingTable = AnalysisDataProcessorBuilder::bindGroupingTable(inputs, processingFunction, infos); + constexpr const int numElements = nested_brace_constructible_size>() / 10; + // set filtered tables for partitions with grouping - homogeneous_apply_refs([&groupingTable](auto& element) { + homogeneous_apply_refs_sized([&groupingTable](auto& element) { analysis_task_parsers::setPartition(element, groupingTable); analysis_task_parsers::bindInternalIndicesPartition(element, &groupingTable); return true; }, - task); + task); if constexpr (sizeof...(Associated) == 0) { // single argument to process - homogeneous_apply_refs([&groupingTable](auto& element) { + homogeneous_apply_refs_sized([&groupingTable](auto& element) { analysis_task_parsers::bindExternalIndicesPartition(element, &groupingTable); analysis_task_parsers::setGroupedCombination(element, groupingTable); return true; }, - task); + task); if constexpr (soa::is_iterator) { for (auto& element : groupingTable) { std::invoke(processingFunction, task, *element); @@ -347,7 +351,7 @@ struct AnalysisDataProcessorBuilder { // pre-bind self indices std::apply( [&task](auto&... t) mutable { - (homogeneous_apply_refs( + (homogeneous_apply_refs_sized( [&t](auto& p) { analysis_task_parsers::bindInternalIndicesPartition(p, &t); return true; @@ -359,12 +363,12 @@ struct AnalysisDataProcessorBuilder { auto binder = [&task, &groupingTable, &associatedTables](auto& x) mutable { x.bindExternalIndices(&groupingTable, &std::get>(associatedTables)...); - homogeneous_apply_refs([&x](auto& t) mutable { + homogeneous_apply_refs_sized([&x](auto& t) mutable { analysis_task_parsers::setPartition(t, x); analysis_task_parsers::bindExternalIndicesPartition(t, &x); return true; }, - task); + task); }; groupingTable.bindExternalIndices(&std::get>(associatedTables)...); @@ -376,11 +380,11 @@ struct AnalysisDataProcessorBuilder { associatedTables); // GroupedCombinations bound separately, as they should be set once for all associated tables - homogeneous_apply_refs([&groupingTable, &associatedTables](auto& t) { + homogeneous_apply_refs_sized([&groupingTable, &associatedTables](auto& t) { analysis_task_parsers::setGroupedCombination(t, groupingTable, associatedTables); return true; }, - task); + task); overwriteInternalIndices(associatedTables, associatedTables); if constexpr (soa::is_iterator>) { auto slicer = GroupSlicer(groupingTable, associatedTables, slices); @@ -394,28 +398,28 @@ struct AnalysisDataProcessorBuilder { associatedSlices); // bind partitions and grouping table - homogeneous_apply_refs([&groupingTable](auto& x) { + homogeneous_apply_refs_sized([&groupingTable](auto& x) { analysis_task_parsers::bindExternalIndicesPartition(x, &groupingTable); return true; }, - task); + task); invokeProcessWithArgs(task, processingFunction, slice.groupingElement(), associatedSlices); } } else { // bind partitions and grouping table - homogeneous_apply_refs([&groupingTable](auto& x) { + homogeneous_apply_refs_sized([&groupingTable](auto& x) { analysis_task_parsers::bindExternalIndicesPartition(x, &groupingTable); return true; }, - task); + task); invokeProcessWithArgs(task, processingFunction, groupingTable, associatedTables); } } } - template + template static void invokeProcessWithArgs(C& task, T processingFunction, G g, std::tuple& at) { std::invoke(processingFunction, task, g, std::get(at)...); @@ -523,16 +527,18 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) std::vector options; std::vector expressionInfos; + constexpr const int numElements = nested_brace_constructible_size>() / 10; + /// make sure options and configurables are set before expression infos are created - homogeneous_apply_refs([&options](auto& element) { return analysis_task_parsers::appendOption(options, element); }, *task.get()); + homogeneous_apply_refs_sized([&options](auto& element) { return analysis_task_parsers::appendOption(options, element); }, *task.get()); /// extract conditions and append them as inputs - homogeneous_apply_refs([&inputs](auto& element) { return analysis_task_parsers::appendCondition(inputs, element); }, *task.get()); + homogeneous_apply_refs_sized([&inputs](auto& element) { return analysis_task_parsers::appendCondition(inputs, element); }, *task.get()); /// parse process functions defined by corresponding configurables if constexpr (requires { &T::process; }) { AnalysisDataProcessorBuilder::inputsFromArgs(&T::process, "default", true, inputs, expressionInfos); } - homogeneous_apply_refs( + homogeneous_apply_refs_sized( [name = name_str, &expressionInfos, &inputs](auto& x) mutable { // this pushes (argumentIndex, processHash, schemaPtr, nullptr) into expressionInfos for arguments that are Filtered/filtered_iterators return AnalysisDataProcessorBuilder::requestInputsFromArgs(x, name, inputs, expressionInfos); @@ -541,39 +547,39 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) // request base tables for spawnable extended tables and indices to be built // this checks for duplications - homogeneous_apply_refs([&inputs](auto& element) { + homogeneous_apply_refs_sized([&inputs](auto& element) { return analysis_task_parsers::requestInputs(inputs, element); }, - *task.get()); + *task.get()); // no static way to check if the task defines any processing, we can only make sure it subscribes to at least something if (inputs.empty() == true) { LOG(warn) << "Task " << name_str << " has no inputs"; } - homogeneous_apply_refs([&outputs, &hash](auto& element) { return analysis_task_parsers::appendOutput(outputs, element, hash); }, *task.get()); + homogeneous_apply_refs_sized([&outputs, &hash](auto& element) { return analysis_task_parsers::appendOutput(outputs, element, hash); }, *task.get()); auto requiredServices = CommonServices::defaultServices(); auto arrowServices = CommonServices::arrowServices(); requiredServices.insert(requiredServices.end(), arrowServices.begin(), arrowServices.end()); - homogeneous_apply_refs([&requiredServices](auto& element) { return analysis_task_parsers::addService(requiredServices, element); }, *task.get()); + homogeneous_apply_refs_sized([&requiredServices](auto& element) { return analysis_task_parsers::addService(requiredServices, element); }, *task.get()); auto algo = AlgorithmSpec::InitCallback{[task = task, expressionInfos](InitContext& ic) mutable { Cache bindingsKeys; Cache bindingsKeysUnsorted; // add preslice declarations to slicing cache definition - homogeneous_apply_refs([&bindingsKeys, &bindingsKeysUnsorted](auto& element) { return analysis_task_parsers::registerCache(element, bindingsKeys, bindingsKeysUnsorted); }, *task.get()); + homogeneous_apply_refs_sized([&bindingsKeys, &bindingsKeysUnsorted](auto& element) { return analysis_task_parsers::registerCache(element, bindingsKeys, bindingsKeysUnsorted); }, *task.get()); - homogeneous_apply_refs([&ic](auto&& element) { return analysis_task_parsers::prepareOption(ic, element); }, *task.get()); - homogeneous_apply_refs([&ic](auto&& element) { return analysis_task_parsers::prepareService(ic, element); }, *task.get()); + homogeneous_apply_refs_sized([&ic](auto&& element) { return analysis_task_parsers::prepareOption(ic, element); }, *task.get()); + homogeneous_apply_refs_sized([&ic](auto&& element) { return analysis_task_parsers::prepareService(ic, element); }, *task.get()); auto& callbacks = ic.services().get(); auto eoscb = [task](EndOfStreamContext& eosContext) { - homogeneous_apply_refs([&eosContext](auto& element) { + homogeneous_apply_refs_sized([&eosContext](auto& element) { analysis_task_parsers::postRunService(eosContext, element); analysis_task_parsers::postRunOutput(eosContext, element); return true; }, - *task.get()); + *task.get()); eosContext.services().get().readyToQuit(QuitRequest::Me); }; @@ -585,84 +591,75 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) } /// update configurables in filters and partitions - homogeneous_apply_refs( + homogeneous_apply_refs_sized( [&ic](auto& element) -> bool { return analysis_task_parsers::updatePlaceholders(ic, element); }, *task.get()); /// create expression trees for filters gandiva trees matched to schemas and store the pointers into expressionInfos - homogeneous_apply_refs([&expressionInfos](auto& element) { + homogeneous_apply_refs_sized([&expressionInfos](auto& element) { return analysis_task_parsers::createExpressionTrees(expressionInfos, element); }, - *task.get()); + *task.get()); /// parse process functions to enable requested grouping caches - note that at this state process configurables have their final values if constexpr (requires { &T::process; }) { AnalysisDataProcessorBuilder::cacheFromArgs(&T::process, true, bindingsKeys, bindingsKeysUnsorted); } - homogeneous_apply_refs( - [&bindingsKeys, &bindingsKeysUnsorted](auto& x) mutable { + homogeneous_apply_refs_sized( + [&bindingsKeys, &bindingsKeysUnsorted](auto& x) { return AnalysisDataProcessorBuilder::requestCacheFromArgs(x, bindingsKeys, bindingsKeysUnsorted); }, *task.get()); ic.services().get().setCaches(std::move(bindingsKeys)); ic.services().get().setCachesUnsorted(std::move(bindingsKeysUnsorted)); - // initialize global caches - homogeneous_apply_refs([&ic](auto& element) { - return analysis_task_parsers::preInitializeCache(ic, element); - }, - *(task.get())); return [task, expressionInfos](ProcessingContext& pc) mutable { // load the ccdb object from their cache - homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::newDataframeCondition(pc.inputs(), element); }, *task.get()); + homogeneous_apply_refs_sized([&pc](auto& element) { return analysis_task_parsers::newDataframeCondition(pc.inputs(), element); }, *task.get()); // reset partitions once per dataframe - homogeneous_apply_refs([](auto& element) { return analysis_task_parsers::newDataframePartition(element); }, *task.get()); + homogeneous_apply_refs_sized([](auto& element) { return analysis_task_parsers::newDataframePartition(element); }, *task.get()); // reset selections for the next dataframe - for (auto& info : expressionInfos) { - info.resetSelection = true; - } + std::ranges::for_each(expressionInfos, [](auto& info) { info.resetSelection = true; }); // reset pre-slice for the next dataframe auto slices = pc.services().get(); - homogeneous_apply_refs([&slices](auto& element) { + homogeneous_apply_refs_sized([&slices](auto& element) { return analysis_task_parsers::updateSliceInfo(element, slices); }, - *(task.get())); + *(task.get())); // initialize local caches - homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::initializeCache(pc, element); }, *(task.get())); + homogeneous_apply_refs_sized([&pc](auto& element) { return analysis_task_parsers::initializeCache(pc, element); }, *(task.get())); // prepare outputs - homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::prepareOutput(pc, element); }, *task.get()); + homogeneous_apply_refs_sized([&pc](auto& element) { return analysis_task_parsers::prepareOutput(pc, element); }, *task.get()); // execute run() if constexpr (requires { task->run(pc); }) { task->run(pc); } // execute process() - if constexpr (requires { AnalysisDataProcessorBuilder::invokeProcess(*(task.get()), pc.inputs(), &T::process, expressionInfos, slices); }) { + if constexpr (requires { &T::process; }) { AnalysisDataProcessorBuilder::invokeProcess(*(task.get()), pc.inputs(), &T::process, expressionInfos, slices); } // execute optional process() - homogeneous_apply_refs( - [&pc, &expressionInfos, &task, &slices](auto& x) mutable { - if constexpr (base_of_template>) { + homogeneous_apply_refs_sized( + [&pc, &expressionInfos, &task, &slices](auto& x) { + if constexpr (is_process_configurable) { if (x.value == true) { AnalysisDataProcessorBuilder::invokeProcess(*task.get(), pc.inputs(), x.process, expressionInfos, slices); return true; } + return false; } return false; }, *task.get()); // prepare delayed outputs - homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::prepareDelayedOutput(pc, element); }, *task.get()); + homogeneous_apply_refs_sized([&pc](auto& element) { return analysis_task_parsers::prepareDelayedOutput(pc, element); }, *task.get()); // finalize outputs - homogeneous_apply_refs([&pc](auto& element) { return analysis_task_parsers::finalizeOutput(pc, element); }, *task.get()); + homogeneous_apply_refs_sized([&pc](auto& element) { return analysis_task_parsers::finalizeOutput(pc, element); }, *task.get()); }; }}; return { name, - // FIXME: For the moment we hardcode this. We could build - // this list from the list of methods actually implemented in the - // task itself. inputs, outputs, algo, diff --git a/Framework/Core/include/Framework/Configurable.h b/Framework/Core/include/Framework/Configurable.h index 3ef90a0eee166..0931884da1ff7 100644 --- a/Framework/Core/include/Framework/Configurable.h +++ b/Framework/Core/include/Framework/Configurable.h @@ -84,10 +84,10 @@ template using MutableConfigurable = Configurable>; template -concept is_configurable = requires(T& t) { - typename T::type; +concept is_configurable = requires(T t) { requires std::same_as; - &T::operator typename T::type; + requires std::same_as; + requires std::same_as::type, decltype(t.value)>; }; using ConfigurableAxis = Configurable, ConfigParamKind::kAxisSpec, ConfigurablePolicyConst, ConfigParamKind::kAxisSpec>>; @@ -99,19 +99,18 @@ concept is_configurable_axis = is_configurable&& T::kind == ConfigParamKind::kAxisSpec; }; -template +template struct ProcessConfigurable : Configurable { - ProcessConfigurable(R (T::*process_)(As...), std::string const& name_, bool&& value_, std::string const& help_) + ProcessConfigurable(void (T::*process_)(As...), std::string const& name_, bool&& value_, std::string const& help_) : process{process_}, Configurable(name_, std::forward(value_), help_) { } - R(T::*process) - (As...); + void (T::*process)(As...); }; template -concept is_process_configurable = is_configurable && requires(T& t) { t.process; }; +concept is_process_configurable = is_configurable && requires(T t) { t.process; }; #define PROCESS_SWITCH(_Class_, _Name_, _Help_, _Default_) \ decltype(o2::framework::ProcessConfigurable{&_Class_ ::_Name_, #_Name_, _Default_, _Help_}) do##_Name_ = o2::framework::ProcessConfigurable{&_Class_ ::_Name_, #_Name_, _Default_, _Help_}; diff --git a/Framework/Core/test/test_Concepts.cxx b/Framework/Core/test/test_Concepts.cxx index ea94c4dfffe5a..982c748e701e4 100644 --- a/Framework/Core/test/test_Concepts.cxx +++ b/Framework/Core/test/test_Concepts.cxx @@ -174,6 +174,7 @@ TEST_CASE("IdentificationConcepts") REQUIRE(is_configurable_axis); REQUIRE(is_process_configurable); + REQUIRE(is_process_configurable); struct : ConfigurableGroup { Configurable c{"", 1, ""}; diff --git a/Framework/Foundation/include/Framework/StructToTuple.h b/Framework/Foundation/include/Framework/StructToTuple.h index 5748329f6a50d..1c7aa62260bd3 100644 --- a/Framework/Foundation/include/Framework/StructToTuple.h +++ b/Framework/Foundation/include/Framework/StructToTuple.h @@ -174,9 +174,9 @@ consteval int nested_brace_constructible_size() return brace_constructible_size() - nesting; } -template () / 10> +template () / 10, typename L> requires(D == 9) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -194,9 +194,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 8) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -214,9 +214,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 7) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -234,9 +234,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 6) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -254,9 +254,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 5) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -274,9 +274,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 4) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -294,9 +294,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 3) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -314,9 +314,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 2) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -334,9 +334,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 1) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -354,9 +354,9 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } -template () / 10> +template () / 10, typename L> requires(D == 0) -auto homogeneous_apply_refs(L l, T&& object) +constexpr auto homogeneous_apply_refs(L l, T&& object) { constexpr int numElements = nested_brace_constructible_size(); // clang-format off @@ -373,6 +373,12 @@ auto homogeneous_apply_refs(L l, T&& object) // clang-format on } +template +constexpr auto homogeneous_apply_refs_sized(L l, T&& object) +{ + return homogeneous_apply_refs(l, object); +} + } // namespace o2::framework #endif // O2_FRAMEWORK_STRUCTTOTUPLE_H_ From 0355d19f2aad1726cdd020029b5eef7b9bb4625b Mon Sep 17 00:00:00 2001 From: Marco van Leeuwen Date: Tue, 17 Feb 2026 19:12:33 +0100 Subject: [PATCH 210/234] [ALICE3] Fix geometry overlaps in tracker (ML/OT) (#15072) --- .../ALICE3/FT3/simulation/src/FT3Module.cxx | 2 +- .../ALICE3/TRK/simulation/src/TRKServices.cxx | 42 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx b/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx index efcad74bc2cb9..9e24247958c06 100644 --- a/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx +++ b/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx @@ -108,7 +108,7 @@ void FT3Module::create_layout(double mZ, int layerNumber, int direction, double double carbonFiberThickness = 0.01; - double foamSpacingThickness = 0.5; + double foamSpacingThickness = 1.0; int dist_offset = 0; diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx index cbe00e8fc9e89..25c59b3c8fd4a 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx @@ -320,26 +320,26 @@ void TRKServices::createMiddleServices(TGeoVolume* motherVolume) const float rMaxMiddleBarrelDisk = 35.f; const float zLengthMiddleBarrel = 64.2f; for (auto& orientation : {Orientation::kASide, Orientation::kCSide}) { - TGeoTube* middleBarrelConnDiskSIO2 = new TGeoTube(Form("TRK_MIDBARCONN_DISK_SIO2sh_%s", orientation == Orientation::kASide ? "bwd" : "fwd"), rMinMiddleBarrelDisk, rMaxMiddleBarrelDisk, siO2FiberThick); - TGeoTube* middleBarrelConnDiskPE = new TGeoTube(Form("TRK_MIDBARCONN_DISK_PEsh_%s", orientation == Orientation::kASide ? "bwd" : "fwd"), rMinMiddleBarrelDisk, rMaxMiddleBarrelDisk, peFiberThick); + TGeoTube* middleBarrelConnDiskSIO2 = new TGeoTube(Form("TRK_MIDBARCONN_DISK_SIO2sh_%s", orientation == Orientation::kASide ? "bwd" : "fwd"), rMinMiddleBarrelDisk, rMaxMiddleBarrelDisk, siO2FiberThick / 2.); + TGeoTube* middleBarrelConnDiskPE = new TGeoTube(Form("TRK_MIDBARCONN_DISK_PEsh_%s", orientation == Orientation::kASide ? "bwd" : "fwd"), rMinMiddleBarrelDisk, rMaxMiddleBarrelDisk, peFiberThick / 2.); TGeoVolume* middleBarrelConnDiskSIO2Volume = new TGeoVolume(Form("TRK_MIDBARCONN_DISK_SIO2_%s", orientation == Orientation::kASide ? "bwd" : "fwd"), middleBarrelConnDiskSIO2, medSiO2); TGeoVolume* middleBarrelConnDiskPEVolume = new TGeoVolume(Form("TRK_MIDBARCONN_DISK_PE_%s", orientation == Orientation::kASide ? "bwd" : "fwd"), middleBarrelConnDiskPE, medPE); middleBarrelConnDiskSIO2Volume->SetLineColor(kGray); middleBarrelConnDiskPEVolume->SetLineColor(kGray); auto* rot = new TGeoRotation("", 0, 0, 180); - auto* combiTransSIO2 = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick / 2 + zLengthMiddleBarrel), rot); - auto* combiTransPE = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick + peFiberThick / 2 + zLengthMiddleBarrel), rot); + auto* combiTransSIO2 = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick / 2. + zLengthMiddleBarrel), rot); + auto* combiTransPE = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick + peFiberThick / 2. + zLengthMiddleBarrel), rot); motherVolume->AddNode(middleBarrelConnDiskSIO2Volume, 1, combiTransSIO2); motherVolume->AddNode(middleBarrelConnDiskPEVolume, 1, combiTransPE); - TGeoTube* middleBarrelConnDiskCu = new TGeoTube(Form("TRK_MIDBARCONN_DISK_CUsh_%s", orientation == Orientation::kASide ? "bwd" : "fwd"), rMinMiddleBarrelDisk, rMaxMiddleBarrelDisk, cuPowerThick); - TGeoTube* middleBarrelConnDiskPEPower = new TGeoTube(Form("TRK_MIDBARCONN_DISK_PEsh_%s", orientation == Orientation::kASide ? "bwd" : "fwd"), rMinMiddleBarrelDisk, rMaxMiddleBarrelDisk, pePowerThick); + TGeoTube* middleBarrelConnDiskCu = new TGeoTube(Form("TRK_MIDBARCONN_DISK_CUsh_%s", orientation == Orientation::kASide ? "bwd" : "fwd"), rMinMiddleBarrelDisk, rMaxMiddleBarrelDisk, cuPowerThick / 2.); + TGeoTube* middleBarrelConnDiskPEPower = new TGeoTube(Form("TRK_MIDBARCONN_DISK_PEsh_%s", orientation == Orientation::kASide ? "bwd" : "fwd"), rMinMiddleBarrelDisk, rMaxMiddleBarrelDisk, pePowerThick / 2.); TGeoVolume* middleBarrelConnDiskCuVolume = new TGeoVolume(Form("TRK_MIDBARCONN_DISK_CU_%s", orientation == Orientation::kASide ? "bwd" : "fwd"), middleBarrelConnDiskCu, medCu); TGeoVolume* middleBarrelConnDiskPEPowerVolume = new TGeoVolume(Form("TRK_MIDBARCONN_DISK_PE_%s", orientation == Orientation::kASide ? "bwd" : "fwd"), middleBarrelConnDiskPEPower, medPE); middleBarrelConnDiskCuVolume->SetLineColor(kGray); middleBarrelConnDiskPEPowerVolume->SetLineColor(kGray); - auto* combiTransCu = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick + peFiberThick + cuPowerThick / 2 + zLengthMiddleBarrel), rot); - auto* combiTransPEPower = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick + peFiberThick + cuPowerThick + pePowerThick / 2 + zLengthMiddleBarrel), rot); + auto* combiTransCu = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick + peFiberThick + cuPowerThick / 2. + zLengthMiddleBarrel), rot); + auto* combiTransPEPower = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick + peFiberThick + cuPowerThick + pePowerThick / 2. + zLengthMiddleBarrel), rot); motherVolume->AddNode(middleBarrelConnDiskCuVolume, 1, combiTransCu); motherVolume->AddNode(middleBarrelConnDiskPEPowerVolume, 1, combiTransPEPower); @@ -357,39 +357,39 @@ void TRKServices::createMiddleServices(TGeoVolume* motherVolume) float rMaxMiddleServicesBarFwd = 74.5f + siO2FiberThick + peFiberThick + cuPowerThick + pePowerThick + puCoolingThick + h2oCoolingThick; for (auto& orientation : {Orientation::kASide, Orientation::kCSide}) { // Create fibers: 3.07mm, 50% SiO2, 50% PE - TGeoTube* middleBarFwdFiberSIO2 = new TGeoTube("TRK_MIDBARFWD_FIBER_SIO2sh", rMinMiddleBarrel, rMaxMiddleServicesBarFwd, siO2FiberThick); - TGeoTube* middleBarFwdFiberPE = new TGeoTube("TRK_MIDBARFWD_FIBER_PEsh", rMinMiddleBarrel, rMaxMiddleServicesBarFwd, peFiberThick); + TGeoTube* middleBarFwdFiberSIO2 = new TGeoTube("TRK_MIDBARFWD_FIBER_SIO2sh", rMinMiddleBarrel, rMaxMiddleServicesBarFwd, siO2FiberThick / 2.); + TGeoTube* middleBarFwdFiberPE = new TGeoTube("TRK_MIDBARFWD_FIBER_PEsh", rMinMiddleBarrel, rMaxMiddleServicesBarFwd, peFiberThick / 2.); TGeoVolume* middleBarFwdFiberSIO2Volume = new TGeoVolume("TRK_MIDBARFWD_FIBER_SIO2", middleBarFwdFiberSIO2, medSiO2); TGeoVolume* middleBarFwdFiberPEVolume = new TGeoVolume("TRK_MIDBARFWD_FIBER_PE", middleBarFwdFiberPE, medPE); middleBarFwdFiberSIO2Volume->SetLineColor(kGray); middleBarFwdFiberPEVolume->SetLineColor(kGray); auto* rot = new TGeoRotation("", 0, 0, 180); - auto* combiTransSIO2 = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick / 2 + zLengthMiddleServices), rot); - auto* combiTransPE = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick + peFiberThick / 2 + zLengthMiddleServices), rot); + auto* combiTransSIO2 = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick / 2. + zLengthMiddleServices), rot); + auto* combiTransPE = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick + peFiberThick / 2. + zLengthMiddleServices), rot); motherVolume->AddNode(middleBarFwdFiberSIO2Volume, 1, combiTransSIO2); motherVolume->AddNode(middleBarFwdFiberPEVolume, 1, combiTransPE); // Create powerlines: 10.9mm, 9% Cu, 91% PE - TGeoTube* middleBarFwdPowerCu = new TGeoTube("TRK_MIDBARFWD_POWER_CUsh", rMinMiddleBarrel, rMaxMiddleServicesBarFwd, cuPowerThick); - TGeoTube* middleBarFwdPowerPE = new TGeoTube("TRK_MIDBARFWD_POWER_PEsh", rMinMiddleBarrel, rMaxMiddleServicesBarFwd, pePowerThick); + TGeoTube* middleBarFwdPowerCu = new TGeoTube("TRK_MIDBARFWD_POWER_CUsh", rMinMiddleBarrel, rMaxMiddleServicesBarFwd, cuPowerThick / 2.); + TGeoTube* middleBarFwdPowerPE = new TGeoTube("TRK_MIDBARFWD_POWER_PEsh", rMinMiddleBarrel, rMaxMiddleServicesBarFwd, pePowerThick / 2.); TGeoVolume* middleBarFwdPowerCuVolume = new TGeoVolume("TRK_MIDBARFWD_POWER_CU", middleBarFwdPowerCu, medCu); TGeoVolume* middleBarFwdPowerPEVolume = new TGeoVolume("TRK_MIDBARFWD_POWER_PE", middleBarFwdPowerPE, medPE); middleBarFwdPowerCuVolume->SetLineColor(kGray); middleBarFwdPowerPEVolume->SetLineColor(kGray); - auto* combiTransCu = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick + peFiberThick + cuPowerThick / 2 + zLengthMiddleServices), rot); - auto* combiTransPEPower = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick + peFiberThick + cuPowerThick + pePowerThick / 2 + zLengthMiddleServices), rot); + auto* combiTransCu = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick + peFiberThick + cuPowerThick / 2. + zLengthMiddleServices), rot); + auto* combiTransPEPower = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick + peFiberThick + cuPowerThick + pePowerThick / 2. + zLengthMiddleServices), rot); motherVolume->AddNode(middleBarFwdPowerCuVolume, 1, combiTransCu); motherVolume->AddNode(middleBarFwdPowerPEVolume, 1, combiTransPEPower); // Create cooling pipes: 4.74mm, 56% PU, 44% H2O - TGeoTube* middleBarFwdCoolingPU = new TGeoTube("TRK_MIDBARFWD_COOLING_PUsh", rMinMiddleBarrel, rMaxMiddleServicesBarFwd, puCoolingThick); - TGeoTube* middleBarFwdCoolingH2O = new TGeoTube("TRK_MIDBARFWD_COOLING_H2Osh", rMinMiddleBarrel, rMaxMiddleServicesBarFwd, h2oCoolingThick); + TGeoTube* middleBarFwdCoolingPU = new TGeoTube("TRK_MIDBARFWD_COOLING_PUsh", rMinMiddleBarrel, rMaxMiddleServicesBarFwd, puCoolingThick / 2.); + TGeoTube* middleBarFwdCoolingH2O = new TGeoTube("TRK_MIDBARFWD_COOLING_H2Osh", rMinMiddleBarrel, rMaxMiddleServicesBarFwd, h2oCoolingThick / 2.); TGeoVolume* middleBarFwdCoolingPUVolume = new TGeoVolume("TRK_MIDBARFWD_COOLING_PU", middleBarFwdCoolingPU, medPU); TGeoVolume* middleBarFwdCoolingH2OVolume = new TGeoVolume("TRK_MIDBARFWD_COOLING_H2O", middleBarFwdCoolingH2O, medH2O); middleBarFwdCoolingPUVolume->SetLineColor(kGray); middleBarFwdCoolingH2OVolume->SetLineColor(kGray); - auto* combiTransCoolingPU = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick + peFiberThick + cuPowerThick + pePowerThick + puCoolingThick / 2 + zLengthMiddleServices), rot); - auto* combiTransCoolingH2O = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick + peFiberThick + cuPowerThick + pePowerThick + puCoolingThick + h2oCoolingThick / 2 + zLengthMiddleServices), rot); + auto* combiTransCoolingPU = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick + peFiberThick + cuPowerThick + pePowerThick + puCoolingThick / 2. + zLengthMiddleServices), rot); + auto* combiTransCoolingH2O = new TGeoCombiTrans(0, 0, (int)orientation * (siO2FiberThick + peFiberThick + cuPowerThick + pePowerThick + puCoolingThick + h2oCoolingThick / 2. + zLengthMiddleServices), rot); motherVolume->AddNode(middleBarFwdCoolingPUVolume, 1, combiTransCoolingPU); motherVolume->AddNode(middleBarFwdCoolingH2OVolume, 1, combiTransCoolingH2O); } @@ -501,4 +501,4 @@ void TRKServices::createOuterBarrelServices(TGeoVolume* motherVolume) motherVolume->AddNode(outerBarrelCoolingH2OVolume, 1, nullptr); } } // namespace trk -} // namespace o2 \ No newline at end of file +} // namespace o2 From e57a6edf96c71b344ede9fe78b4b0e3c69335069 Mon Sep 17 00:00:00 2001 From: Pavel Larionov Date: Tue, 17 Feb 2026 19:15:56 +0100 Subject: [PATCH 211/234] Configurable VD design, set def to IRIS 4, remove IRIS disks (#15055) --- .../TRK/base/include/TRKBase/TRKBaseParam.h | 9 ++++++ .../ALICE3/TRK/simulation/src/Detector.cxx | 28 ++++++++++++++++--- .../TRK/simulation/src/VDGeometryBuilder.cxx | 2 +- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h index 7f2f7f32b79d9..d5e11313c0f0c 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h +++ b/Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h @@ -31,6 +31,13 @@ enum eLayout { kStaggered, }; +enum eVDLayout { + kIRIS4 = 0, + kIRISFullCyl, + kIRIS5, + kIRIS4a, +}; + struct TRKBaseParam : public o2::conf::ConfigurableParamHelper { std::string configFile = ""; float serviceTubeX0 = 0.02f; // X0 Al2O3 @@ -40,9 +47,11 @@ struct TRKBaseParam : public o2::conf::ConfigurableParamHelper { eLayout layoutML = kTurboStaves; // Type of segmentation for the middle layers eLayout layoutOL = kStaggered; // Type of segmentation for the outer layers + eVDLayout layoutVD = kIRIS4; // VD detector layout design eLayout getLayoutML() const { return layoutML; } eLayout getLayoutOL() const { return layoutOL; } + eVDLayout getLayoutVD() const { return layoutVD; } O2ParamDef(TRKBaseParam, "TRKBase"); }; diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx index 06fd2d9670b67..556b016f22553 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx @@ -261,12 +261,32 @@ void Detector::createGeometry() mServices.createServices(vTRK); // Build the VD using the petal builder - // Choose the VD design (here: IRIS4 by default). - // You can wire this to a parameter in TRKBaseParam if desired. - // Alternatives: createIRIS5Geometry(vTRK); createIRIS4aGeometry(vTRK); + // Choose the VD design based on TRKBaseParam.layoutVD + auto& trkPars = TRKBaseParam::Instance(); o2::trk::clearVDSensorRegistry(); - o2::trk::createIRISGeometryFullCyl(vTRK); + + switch (trkPars.layoutVD) { + case kIRIS4: + LOG(info) << "Building VD with IRIS4 layout"; + o2::trk::createIRIS4Geometry(vTRK); + break; + case kIRISFullCyl: + LOG(info) << "Building VD with IRIS fully cylindrical layout"; + o2::trk::createIRISGeometryFullCyl(vTRK); + break; + case kIRIS5: + LOG(info) << "Building VD with IRIS5 layout"; + o2::trk::createIRIS5Geometry(vTRK); + break; + case kIRIS4a: + LOG(info) << "Building VD with IRIS4a layout"; + o2::trk::createIRIS4aGeometry(vTRK); + break; + default: + LOG(fatal) << "Unknown VD layout option: " << static_cast(trkPars.layoutVD); + break; + } // Fill sensor names from registry right after geometry creation const auto& regs = o2::trk::vdSensorRegistry(); diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/VDGeometryBuilder.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/VDGeometryBuilder.cxx index 6ce04bb8443ef..b06faa38211bb 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/VDGeometryBuilder.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/VDGeometryBuilder.cxx @@ -749,7 +749,7 @@ static TGeoVolume* buildPetalAssembly(int nPetals, /*fullCylindricalRadialWalls=*/fullCylinders); addBarrelLayers(petalAsm, nPetals, petalID, rectangularL0, fullCylinders); - addDisks(petalAsm, nPetals, petalID, fullCylinders); + // addDisks(petalAsm, nPetals, petalID, fullCylinders); // disks removed according to the v3b layout addColdPlate(petalAsm, nPetals, petalID, /*fullCylinders=*/false); addIRISServiceModulesSegmented(petalAsm, nPetals); From e5768cde630297876b47f1c24b5da3489f56228a Mon Sep 17 00:00:00 2001 From: Andrea Sofia Triolo Date: Tue, 17 Feb 2026 19:16:53 +0100 Subject: [PATCH 212/234] ALICE3-TRK: adapt ordering key for digits to the large number of columns in the VD (#15070) --- .../simulation/include/TRKSimulation/ChipDigitsContainer.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipDigitsContainer.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipDigitsContainer.h index 658fb823bb596..73c95b04c45e3 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipDigitsContainer.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipDigitsContainer.h @@ -29,6 +29,12 @@ class ChipDigitsContainer : public o2::itsmft::ChipDigitsContainer using Segmentation = SegmentationChip; + /// Get global ordering key made of readout frame, column and row + static ULong64_t getOrderingKey(UInt_t roframe, UShort_t row, UShort_t col) + { + return (static_cast(roframe) << (8 * sizeof(UInt_t))) + (static_cast(col) << (8 * sizeof(Short_t))) + row; + } + ClassDefNV(ChipDigitsContainer, 1); }; From 06150434b8a30967fb5449016758b0441748f0b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Jacazio?= Date: Tue, 17 Feb 2026 21:54:34 +0100 Subject: [PATCH 213/234] A3: Add geometries for IOTOF (#15073) - fix enabling and disabling of backward TOF - add v3b versions of IOTOF --- .../base/include/IOTOFBase/IOTOFBaseParam.h | 1 + .../include/IOTOFSimulation/Detector.h | 2 +- .../ALICE3/IOTOF/simulation/src/Detector.cxx | 73 ++++++++++++++----- 3 files changed, 56 insertions(+), 20 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h index 10d8c5ced94dd..bf605797cbfe5 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h @@ -25,6 +25,7 @@ struct IOTOFBaseParam : public o2::conf::ConfigurableParamHelper bool enableOuterTOF = true; bool enableForwardTOF = true; bool enableBackwardTOF = true; + std::string detectorPattern = ""; O2ParamDef(IOTOFBaseParam, "IOTOFBase"); }; diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Detector.h b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Detector.h index 1f3b2f4fe9fac..f39a43733ccab 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Detector.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Detector.h @@ -60,7 +60,7 @@ class Detector : public o2::base::DetImpl return nullptr; } - void configLayers(bool itof = true, bool otof = true, bool ftof = true, bool btof = true); + void configLayers(bool itof = true, bool otof = true, bool ftof = true, bool btof = true, std::string pattern = ""); void configServices(); void createMaterials(); diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx index a2bba7cc5fe35..3a971e81a610d 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx @@ -20,8 +20,6 @@ #include "IOTOFSimulation/Detector.h" #include "IOTOFBase/IOTOFBaseParam.h" -using o2::itsmft::Hit; - namespace o2 { namespace iotof @@ -40,7 +38,9 @@ Detector::Detector(bool active) mHits(o2::utils::createSimVector()) { auto& iotofPars = IOTOFBaseParam::Instance(); - configLayers(iotofPars.enableInnerTOF, iotofPars.enableOuterTOF, iotofPars.enableForwardTOF); + configLayers(iotofPars.enableInnerTOF, iotofPars.enableOuterTOF, + iotofPars.enableForwardTOF, iotofPars.enableBackwardTOF, + iotofPars.detectorPattern); } Detector::~Detector() @@ -56,19 +56,54 @@ void Detector::ConstructGeometry() createGeometry(); } -void Detector::configLayers(bool itof, bool otof, bool ftof, bool btof) +void Detector::configLayers(bool itof, bool otof, bool ftof, bool btof, std::string pattern) { + + float radiusInnerTof = 19.f; + float radiusOuterTof = 85.f; + float lengthInnerTof = 124.f; + float lengthOuterTof = 680.f; + std::pair radiusRangeDiskTof = {15.f, 100.f}; + float zForwardTof = 370.f; + if (pattern == "") { + } else if (pattern == "v3b") { + LOG(info) << "Configuring IOTOF layers with v3b pattern"; + ftof = false; + btof = false; + } else if (pattern == "v3b1a") { + lengthOuterTof = 500.f; + zForwardTof = 270.f; + radiusRangeDiskTof = {30.f, 100.f}; + } else if (pattern == "v3b1b") { + lengthOuterTof = 500.f; + zForwardTof = 200.f; + radiusRangeDiskTof = {20.f, 68.f}; + } else if (pattern == "v3b2a") { + lengthOuterTof = 440.f; + zForwardTof = 270.f; + radiusRangeDiskTof = {30.f, 120.f}; + } else if (pattern == "v3b2b") { + lengthOuterTof = 440.f; + zForwardTof = 200.f; + radiusRangeDiskTof = {20.f, 68.f}; + } else if (pattern == "v3b3") { + lengthOuterTof = 580.f; + zForwardTof = 200.f; + radiusRangeDiskTof = {20.f, 68.f}; + } else { + LOG(fatal) << "IOTOF layer pattern " << pattern << " not recognized, exiting"; + } if (itof) { - mITOFLayer = ITOFLayer(std::string{GeometryTGeo::getITOFLayerPattern()}, 19.f, 0.f, 124.f, 0.f, 0.02f, true); // iTOF + mITOFLayer = ITOFLayer(std::string{GeometryTGeo::getITOFLayerPattern()}, radiusInnerTof, 0.f, lengthInnerTof, 0.f, 0.02f, true); // iTOF } if (otof) { - mOTOFLayer = OTOFLayer(std::string{GeometryTGeo::getOTOFLayerPattern()}, 85.f, 0.f, 680.f, 0.f, 0.02f, true); // oTOF + mOTOFLayer = OTOFLayer(std::string{GeometryTGeo::getOTOFLayerPattern()}, radiusOuterTof, 0.f, lengthOuterTof, 0.f, 0.02f, true); // oTOF } if (ftof) { - mFTOFLayer = FTOFLayer(std::string{GeometryTGeo::getFTOFLayerPattern()}, 15.f, 100.f, 0.f, 370.f, 0.02f, false); // fTOF + mFTOFLayer = FTOFLayer(std::string{GeometryTGeo::getFTOFLayerPattern()}, radiusRangeDiskTof.first, radiusRangeDiskTof.second, 0.f, zForwardTof, 0.02f, false); // fTOF } if (btof) { - mBTOFLayer = BTOFLayer(std::string{GeometryTGeo::getBTOFLayerPattern()}, 15.f, 100.f, 0.f, -370.f, 0.02f, false); // bTOF + mBTOFLayer = BTOFLayer(std::string{GeometryTGeo::getBTOFLayerPattern()}, radiusRangeDiskTof.first, radiusRangeDiskTof.second, 0.f, -zForwardTof, 0.02f, false); // bTOF } } @@ -214,28 +249,28 @@ bool Detector::ProcessHits(FairVolume* vol) bool startHit = false, stopHit = false; unsigned char status = 0; if (fMC->IsTrackEntering()) { - status |= Hit::kTrackEntering; + status |= o2::itsmft::Hit::kTrackEntering; } if (fMC->IsTrackInside()) { - status |= Hit::kTrackInside; + status |= o2::itsmft::Hit::kTrackInside; } if (fMC->IsTrackExiting()) { - status |= Hit::kTrackExiting; + status |= o2::itsmft::Hit::kTrackExiting; } if (fMC->IsTrackOut()) { - status |= Hit::kTrackOut; + status |= o2::itsmft::Hit::kTrackOut; } if (fMC->IsTrackStop()) { - status |= Hit::kTrackStopped; + status |= o2::itsmft::Hit::kTrackStopped; } if (fMC->IsTrackAlive()) { - status |= Hit::kTrackAlive; + status |= o2::itsmft::Hit::kTrackAlive; } // track is entering or created in the volume - if ((status & Hit::kTrackEntering) || (status & Hit::kTrackInside && !mTrackData.mHitStarted)) { + if ((status & o2::itsmft::Hit::kTrackEntering) || (status & o2::itsmft::Hit::kTrackInside && !mTrackData.mHitStarted)) { startHit = true; - } else if ((status & (Hit::kTrackExiting | Hit::kTrackOut | Hit::kTrackStopped))) { + } else if ((status & (o2::itsmft::Hit::kTrackExiting | o2::itsmft::Hit::kTrackOut | o2::itsmft::Hit::kTrackStopped))) { stopHit = true; } @@ -264,9 +299,9 @@ bool Detector::ProcessHits(FairVolume* vol) fMC->CurrentVolOffID(3, halfstave); fMC->CurrentVolOffID(4, stave); - Hit* p = addHit(stack->GetCurrentTrackNumber(), lay, mTrackData.mPositionStart.Vect(), positionStop.Vect(), - mTrackData.mMomentumStart.Vect(), mTrackData.mMomentumStart.E(), positionStop.T(), - mTrackData.mEnergyLoss, mTrackData.mTrkStatusStart, status); + o2::itsmft::Hit* p = addHit(stack->GetCurrentTrackNumber(), lay, mTrackData.mPositionStart.Vect(), positionStop.Vect(), + mTrackData.mMomentumStart.Vect(), mTrackData.mMomentumStart.E(), positionStop.T(), + mTrackData.mEnergyLoss, mTrackData.mTrkStatusStart, status); // RS: not sure this is needed // Increment number of Detector det points in TParticle From 41d9be4b011d3c9cc04742b271e814661002379d Mon Sep 17 00:00:00 2001 From: Maximiliano Puccio Date: Tue, 17 Feb 2026 22:08:43 +0100 Subject: [PATCH 214/234] [ALICE3] Adapt CA for 2T simulations (#15075) --- .../reconstruction/include/TRKReconstruction/TimeFrame.h | 3 --- .../Upgrades/ALICE3/TRK/reconstruction/src/TimeFrame.cxx | 7 ++++++- Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx | 7 ++++++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/reconstruction/include/TRKReconstruction/TimeFrame.h b/Detectors/Upgrades/ALICE3/TRK/reconstruction/include/TRKReconstruction/TimeFrame.h index d2ca6fba132e1..f42a1c897efb6 100644 --- a/Detectors/Upgrades/ALICE3/TRK/reconstruction/include/TRKReconstruction/TimeFrame.h +++ b/Detectors/Upgrades/ALICE3/TRK/reconstruction/include/TRKReconstruction/TimeFrame.h @@ -62,9 +62,6 @@ class TimeFrame : public o2::its::TimeFrame /// \param nEvents Number of events to process /// \param inROFpileup Number of events per ROF void getPrimaryVerticesFromMC(TTree* mcHeaderTree, int nRofs, Long64_t nEvents, int inROFpileup); - - private: - ClassDefNV(TimeFrame, 1); }; } // namespace trk diff --git a/Detectors/Upgrades/ALICE3/TRK/reconstruction/src/TimeFrame.cxx b/Detectors/Upgrades/ALICE3/TRK/reconstruction/src/TimeFrame.cxx index 686270826049b..610a08450d5ee 100644 --- a/Detectors/Upgrades/ALICE3/TRK/reconstruction/src/TimeFrame.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/reconstruction/src/TimeFrame.cxx @@ -64,10 +64,12 @@ int TimeFrame::loadROFsFromHitTree(TTree* hitsTree, GeometryTGeo* gman, } int subDetID = gman->getSubDetID(hit.GetDetectorID()); const int layer = startLayer[subDetID] + gman->getLayer(hit.GetDetectorID()); + if (layer >= nLayers) { + continue; + } ++clusterCountPerLayer[layer]; totalNHits++; } - trkHit->clear(); } // Reserve memory for all layers @@ -106,6 +108,9 @@ int TimeFrame::loadROFsFromHitTree(TTree* hitsTree, GeometryTGeo* gman, o2::math_utils::Point3D gloXYZ; o2::math_utils::Point3D trkXYZ; float r{0.f}; + if (layer >= nLayers) { + continue; + } if (layer >= 3) { int chipID = hit.GetDetectorID(); alpha = gman->getSensorRefAlphaMLOT(chipID); diff --git a/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx b/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx index 8f26478f4496e..8fc67f0fa5567 100644 --- a/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx @@ -10,11 +10,13 @@ // or submit itself to any jurisdiction. #include +#include #include "DetectorsBase/GeometryManager.h" #include "ITStracking/TimeFrame.h" #include "ITStracking/Configuration.h" #include "Field/MagneticField.h" +#include "Field/MagFieldParam.h" #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/CCDBParamSpec.h" @@ -276,7 +278,7 @@ void TrackerDPL::run(ProcessingContext& pc) itsTrackerTraits.adoptTimeFrame(static_cast*>(&timeFrame)); itsTracker.adoptTimeFrame(timeFrame); itsTrackerTraits.setBz(mHitRecoConfig["geometry"]["bz"].get()); - auto field = o2::field::MagneticField::createNominalField(std::round(mHitRecoConfig["geometry"]["bz"].get()), true); + auto field = new field::MagneticField("ALICE3Mag", "ALICE 3 Magnetic Field", mHitRecoConfig["geometry"]["bz"].get() / 5.f, 0.0, o2::field::MagFieldParam::k5kGUniform); TGeoGlobalMagField::Instance()->SetField(field); TGeoGlobalMagField::Instance()->Lock(); @@ -291,6 +293,7 @@ void TrackerDPL::run(ProcessingContext& pc) itsTrackerTraits.updateTrackingParameters(trackingParams); + const auto trackingLoopStart = std::chrono::steady_clock::now(); for (size_t iter{0}; iter < trackingParams.size(); ++iter) { LOGP(info, "{}", trackingParams[iter].asString()); timeFrame.initialise(iter, trackingParams[iter], 11, false); @@ -304,6 +307,8 @@ void TrackerDPL::run(ProcessingContext& pc) LOGP(info, "Number of roads in iteration {}: {}", iter, timeFrame.getNumberOfTracks()); itsTrackerTraits.extendTracks(iter); } + const auto trackingLoopElapsedMs = std::chrono::duration_cast(std::chrono::steady_clock::now() - trackingLoopStart).count(); + LOGP(info, "Tracking iterations block took {} ms", trackingLoopElapsedMs); itsTracker.computeTracksMClabels(); From d95be4db7b5fe479e7adbe8b45094f628d6d97ea Mon Sep 17 00:00:00 2001 From: Sandro Wenzel Date: Tue, 17 Feb 2026 19:47:42 +0100 Subject: [PATCH 215/234] o2-sim: Possibility to switch between TGeo and Geant4 navigation --- Common/SimConfig/include/SimConfig/G4Params.h | 9 +++++++++ Common/SimConfig/src/SimConfigLinkDef.h | 1 + Detectors/gconfig/g4Config.C | 11 ++++++++++- Steer/src/O2MCApplication.cxx | 6 ++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/Common/SimConfig/include/SimConfig/G4Params.h b/Common/SimConfig/include/SimConfig/G4Params.h index fd36ae046d520..aa8aa05263c0a 100644 --- a/Common/SimConfig/include/SimConfig/G4Params.h +++ b/Common/SimConfig/include/SimConfig/G4Params.h @@ -33,6 +33,13 @@ enum class EG4Physics { kUSER = 8 /* allows to give own string combination */ }; +// enumerating possible geometry navigation modes +// (understanding that geometry description is always done with TGeo) +enum class EG4Nav { + kTGeo = 0, /* navigate with TGeo */ + kG4 = 1 /* navigate with G4 native geometry */ +}; + // parameters to influence the G4 engine struct G4Params : public o2::conf::ConfigurableParamHelper { EG4Physics physicsmode = EG4Physics::kFTFP_BERT_EMV_optical; // default physics mode with which to configure G4 @@ -40,6 +47,8 @@ struct G4Params : public o2::conf::ConfigurableParamHelper { std::string configMacroFile = ""; // a user provided g4Config.in file (otherwise standard one fill be taken) std::string userPhysicsList = ""; // possibility to directly give physics list as string + EG4Nav navmode = EG4Nav::kTGeo; // geometry navigation mode (default TGeo) + std::string const& getPhysicsConfigString() const; O2ParamDef(G4Params, "G4"); diff --git a/Common/SimConfig/src/SimConfigLinkDef.h b/Common/SimConfig/src/SimConfigLinkDef.h index 9c27536be5eb8..a1315e24ffedd 100644 --- a/Common/SimConfig/src/SimConfigLinkDef.h +++ b/Common/SimConfig/src/SimConfigLinkDef.h @@ -29,6 +29,7 @@ #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::conf::DigiParams> + ; #pragma link C++ enum o2::conf::EG4Physics; +#pragma link C++ enum o2::conf::EG4Nav; #pragma link C++ enum o2::conf::SimFieldMode; #pragma link C++ struct o2::conf::G4Params + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::conf::G4Params> + ; diff --git a/Detectors/gconfig/g4Config.C b/Detectors/gconfig/g4Config.C index 8f74c0105dbf5..c2b1fbd433e4b 100644 --- a/Detectors/gconfig/g4Config.C +++ b/Detectors/gconfig/g4Config.C @@ -100,7 +100,16 @@ void Config() auto& g4Params = ::o2::conf::G4Params::Instance(); auto& physicsSetup = g4Params.getPhysicsConfigString(); std::cout << "PhysicsSetup wanted " << physicsSetup << "\n"; - auto runConfiguration = new TG4RunConfiguration("geomRoot", physicsSetup, "stepLimiter+specialCuts", + std::string geomNavStr; + if (g4Params.navmode == o2::conf::EG4Nav::kTGeo) { + geomNavStr = "geomRoot"; + } else if (g4Params.navmode == o2::conf::EG4Nav::kG4) { + geomNavStr = "geomVMC+RootToGeant4"; + } else { + LOG(fatal) << "Unsupported geometry navigation mode"; + } + + auto runConfiguration = new TG4RunConfiguration(geomNavStr, physicsSetup, "stepLimiter+specialCuts", specialStacking, mtMode); /// avoid the use of G4BACKTRACE (it seems to inferfere with process logic in o2-sim) setenv("G4BACKTRACE", "none", 1); diff --git a/Steer/src/O2MCApplication.cxx b/Steer/src/O2MCApplication.cxx index f832ab70ab121..1e3f925042d01 100644 --- a/Steer/src/O2MCApplication.cxx +++ b/Steer/src/O2MCApplication.cxx @@ -42,6 +42,7 @@ #include #include #include +#include "SimConfig/G4Params.h" namespace o2 { @@ -223,6 +224,11 @@ bool O2MCApplicationBase::MisalignGeometry() void O2MCApplicationBase::fixTGeoRuntimeShapes() { + auto& g4Params = o2::conf::G4Params::Instance(); + if (g4Params.navmode != o2::conf::EG4Nav::kTGeo) { + return; + } + // Replace TGeo shapes by other ones for performance or other reasons. // Should only affect runtime of simulation. From d384645a99a311b75d221ca280d924a6bdfbb787 Mon Sep 17 00:00:00 2001 From: Andrea Sofia Triolo Date: Wed, 18 Feb 2026 15:11:43 +0100 Subject: [PATCH 216/234] ALICE3-TRK: fix detector ID assignment to hits (#15074) --- .../Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx index b32c89164f18a..059a35520c1a0 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx @@ -416,15 +416,15 @@ TString GeometryTGeo::getMatrixPath(int index) const // build the path if (subDetID == 0) { // VD if (disk >= 0) { - path += Form("%s_%d_%d/", getTRKPetalAssemblyPattern(), petalcase, petalcase + 1); // PETAL_n - path += Form("%s%d_%s%d_1/", getTRKPetalPattern(), petalcase, getTRKPetalDiskPattern(), disk); // PETALCASEx_DISKy_1 - // path += Form("%s%d_%s%d_%s%d_1/", getTRKPetalPattern(), petalcase, getTRKPetalDiskPattern(), disk, getTRKChipPattern(), disk); // PETALCASEx_DISKy_TRKChipy_1 + path += Form("%s_%d_%d/", getTRKPetalAssemblyPattern(), petalcase, petalcase + 1); // PETAL_n + path += Form("%s%d_%s%d_1/", getTRKPetalPattern(), petalcase, getTRKPetalDiskPattern(), disk); // PETALCASEx_DISKy_1 + path += Form("%s%d_%s%d_%s%d_1/", getTRKPetalPattern(), petalcase, getTRKPetalDiskPattern(), disk, getTRKChipPattern(), disk); // PETALCASEx_DISKy_TRKChipy_1 path += Form("%s%d_%s%d_%s%d_1/", getTRKPetalPattern(), petalcase, getTRKPetalDiskPattern(), disk, getTRKSensorPattern(), disk); // PETALCASEx_DISKy_TRKSensory_1 } else if (layer >= 0) { path += Form("%s_%d_%d/", getTRKPetalAssemblyPattern(), petalcase, petalcase + 1); // PETAL_n path += Form("%s%d_%s%d_1/", getTRKPetalPattern(), petalcase, getTRKPetalLayerPattern(), layer); // PETALCASEx_LAYERy_1 // path += Form("%s%d_%s%d_%s%d_1/", getTRKPetalPattern(), petalcase, getTRKPetalLayerPattern(), layer, getTRKStavePattern(), layer); // PETALCASEx_LAYERy_TRKStavey_1 - // path += Form("%s%d_%s%d_%s%d_1/", getTRKPetalPattern(), petalcase, getTRKPetalLayerPattern(), layer, getTRKChipPattern(), layer); // PETALCASEx_LAYERy_TRKChipy_1 + path += Form("%s%d_%s%d_%s%d_1/", getTRKPetalPattern(), petalcase, getTRKPetalLayerPattern(), layer, getTRKChipPattern(), layer); // PETALCASEx_LAYERy_TRKChipy_1 path += Form("%s%d_%s%d_%s%d_1/", getTRKPetalPattern(), petalcase, getTRKPetalLayerPattern(), layer, getTRKSensorPattern(), layer); // PETALCASEx_LAYERy_TRKSensory_1 } } else if (subDetID == 1) { // MLOT @@ -962,9 +962,9 @@ int GeometryTGeo::extractNumberOfChipsPerPetalVD() const for (int i = 0; i < subNodes->GetEntriesFast(); i++) { auto* subNode = dynamic_cast(subNodes->At(i)); - if (strstr(subNode->GetName(), getTRKSensorPattern()) != nullptr) { + if (strstr(subNode->GetName(), getTRKChipPattern()) != nullptr) { numberOfChips++; - LOGP(debug, "Found sensor in {}: {}", nodeName, subNode->GetName()); + LOGP(debug, "Found chip in {}: {}", nodeName, subNode->GetName()); } } } From 0b483951ab025a97601f15d861ba4df8de3c396e Mon Sep 17 00:00:00 2001 From: altsybee Date: Thu, 19 Feb 2026 07:54:50 +0100 Subject: [PATCH 217/234] [ALICE3] Change to upper-case 'S' in "FT3sensor_*" strings (#15078) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Change to upper-case 'S' in "FT3sensor_*" * Change to upper-case 'S' in "FT3sensor_*" in FT3Module.cxx * Update comments in exportLayout method Clarified comments in exportLayout function. --------- Co-authored-by: Nicolò Jacazio --- Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx | 7 ++++--- .../Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx index 9303979ada930..4b139272834f1 100644 --- a/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx @@ -129,7 +129,8 @@ void Detector::buildFT3FromFile(std::string configFileName) //_________________________________________________________________________________________________ void Detector::exportLayout() { - // Export FT3 Layout description to file. One line per disk + // Export FT3 Layout description to file. + // One line per disk: // z_layer r_in r_out Layerx2X0 std::string configFileName = "FT3_layout.cfg"; @@ -795,8 +796,8 @@ void Detector::defineSensitiveVolumes() AddSensitiveVolume(v); } else { // OT disks for (int sensor_count = 0; sensor_count < MAX_SENSORS; ++sensor_count) { - std::string sensor_name_front = "FT3sensor_front_" + std::to_string(iLayer) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); - std::string sensor_name_back = "FT3sensor_back_" + std::to_string(iLayer) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); + std::string sensor_name_front = "FT3Sensor_front_" + std::to_string(iLayer) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); + std::string sensor_name_back = "FT3Sensor_back_" + std::to_string(iLayer) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); v = geoManager->GetVolume(sensor_name_front.c_str()); if (v) { AddSensitiveVolume(v); diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx b/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx index 9e24247958c06..9318554837706 100644 --- a/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx +++ b/Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx @@ -481,7 +481,7 @@ void FT3Module::create_layout(double mZ, int layerNumber, int direction, double if (sensor_width == 2.5) { // silicon - std::string sensor_name = "FT3sensor_front_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); + std::string sensor_name = "FT3Sensor_front_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); sensor = geoManager->MakeBox(sensor_name.c_str(), siliconMed, active_width / 2, active_height / 2, silicon_thickness / 2); sensor->SetLineColor(SiColor); sensor->SetFillColorAlpha(SiColor, 0.4); @@ -495,7 +495,7 @@ void FT3Module::create_layout(double mZ, int layerNumber, int direction, double } else { - std::string sensor_name = "FT3sensor_front_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); + std::string sensor_name = "FT3Sensor_front_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); sensor = geoManager->MakeBox(sensor_name.c_str(), siliconMed, active_width / 2, sensor_height / 2, silicon_thickness / 2); sensor->SetLineColor(SiColor); sensor->SetFillColorAlpha(SiColor, 0.4); @@ -652,7 +652,7 @@ void FT3Module::create_layout(double mZ, int layerNumber, int direction, double if (sensor_width == 2.5) { - std::string sensor_name = "FT3sensor_back_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); + std::string sensor_name = "FT3Sensor_back_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); sensor = geoManager->MakeBox(sensor_name.c_str(), siliconMed, active_width / 2, active_height / 2, silicon_thickness / 2); sensor->SetLineColor(SiColor); sensor->SetFillColorAlpha(SiColor, 0.4); @@ -666,7 +666,7 @@ void FT3Module::create_layout(double mZ, int layerNumber, int direction, double } else { // active (4.6 cm centered) - std::string sensor_name = "FT3sensor_back_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); + std::string sensor_name = "FT3Sensor_back_" + std::to_string(layerNumber) + "_" + std::to_string(direction) + "_" + std::to_string(sensor_count); sensor = geoManager->MakeBox(sensor_name.c_str(), siliconMed, active_width / 2, sensor_height / 2, silicon_thickness / 2); sensor->SetLineColor(SiColor); sensor->SetFillColorAlpha(SiColor, 0.4); From db8db2f046de80b4b70c4de41d0b05e07568aefd Mon Sep 17 00:00:00 2001 From: Roman Lietava Date: Thu, 19 Feb 2026 10:17:05 +0100 Subject: [PATCH 218/234] Ctpdev: getting list of unmasked inputs (#15082) * dev:CTpCfg list of used inputs * clang --- .../include/DataFormatsCTP/Configuration.h | 3 ++- .../Detectors/CTP/src/Configuration.cxx | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/DataFormats/Detectors/CTP/include/DataFormatsCTP/Configuration.h b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Configuration.h index e9464089d71fc..ff1462084d53d 100644 --- a/DataFormats/Detectors/CTP/include/DataFormatsCTP/Configuration.h +++ b/DataFormats/Detectors/CTP/include/DataFormatsCTP/Configuration.h @@ -214,7 +214,8 @@ struct CtpCfg { uint32_t orbitShift = 0; uint32_t irInputs_1_24 = 0; uint32_t irInputs_25_48 = 0; - ClassDefNV(CtpCfg, 1) + std::vector listOfUsedInputs(); + ClassDefNV(CtpCfg, 2) }; } // namespace ctp } // namespace o2 diff --git a/DataFormats/Detectors/CTP/src/Configuration.cxx b/DataFormats/Detectors/CTP/src/Configuration.cxx index 61e51bcb20d91..98458ef06d1d3 100644 --- a/DataFormats/Detectors/CTP/src/Configuration.cxx +++ b/DataFormats/Detectors/CTP/src/Configuration.cxx @@ -1227,9 +1227,24 @@ int CtpCfg::readAndSave(std::string& path) } return 0; } - +std::vector CtpCfg::listOfUsedInputs() +{ + std::cout << std::hex << "0x" << irInputs_1_24 << " " << irInputs_25_48 << std::dec << std::endl; + std::vector inputList; + for (int i = 0; i < 24; i++) { + if ((1ul << i) & irInputs_1_24) { + inputList.push_back(i); + } + } + for (int i = 0; i < 24; i++) { + if ((1ul << i) & irInputs_25_48) { + inputList.push_back(i + 24); + } + } + return inputList; +} std::ostream& o2::ctp::operator<<(std::ostream& in, const o2::ctp::CTPConfiguration& conf) { conf.printStream(in); return in; -} +} \ No newline at end of file From efa08980b26cf9ee523abf6d427b7e41dee1ed0d Mon Sep 17 00:00:00 2001 From: Maximiliano Puccio Date: Thu, 19 Feb 2026 10:18:54 +0100 Subject: [PATCH 219/234] [ITS] Protect ultra low pt selections at the tracklet level (#15079) Checked on Pb-Pb simulation that this does not change the number of reconstructed tracks --- Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx b/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx index 70f4e3d1d3fc7..29fb4ac4c69b5 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx @@ -344,7 +344,6 @@ void TimeFrame::initialise(const int iteration, const TrackingParameter mMSangles.resize(trkParam.NLayers); mPhiCuts.resize(mClusters.size() - 1, 0.f); - float oneOverR{0.001f * 0.3f * std::abs(mBz) / trkParam.TrackletMinPt}; for (unsigned int iLayer{0}; iLayer < nLayers; ++iLayer) { mMSangles[iLayer] = math_utils::MSangle(0.14f, trkParam.TrackletMinPt, trkParam.LayerxX0[iLayer]); @@ -352,12 +351,14 @@ void TimeFrame::initialise(const int iteration, const TrackingParameter if (iLayer < mClusters.size() - 1) { const float& r1 = trkParam.LayerRadii[iLayer]; const float& r2 = trkParam.LayerRadii[iLayer + 1]; + oneOverR = (0.5 * oneOverR >= 1.f / r2) ? 2.f / r2 - o2::constants::math::Almost0 : oneOverR; const float res1 = o2::gpu::CAMath::Hypot(trkParam.PVres, mPositionResolution[iLayer]); const float res2 = o2::gpu::CAMath::Hypot(trkParam.PVres, mPositionResolution[iLayer + 1]); const float cosTheta1half = o2::gpu::CAMath::Sqrt(1.f - math_utils::Sq(0.5f * r1 * oneOverR)); const float cosTheta2half = o2::gpu::CAMath::Sqrt(1.f - math_utils::Sq(0.5f * r2 * oneOverR)); float x = r2 * cosTheta1half - r1 * cosTheta2half; float delta = o2::gpu::CAMath::Sqrt(1.f / (1.f - 0.25f * math_utils::Sq(x * oneOverR)) * (math_utils::Sq(0.25f * r1 * r2 * math_utils::Sq(oneOverR) / cosTheta2half + cosTheta1half) * math_utils::Sq(res1) + math_utils::Sq(0.25f * r1 * r2 * math_utils::Sq(oneOverR) / cosTheta1half + cosTheta2half) * math_utils::Sq(res2))); + /// the expression std::asin(0.5f * x * oneOverR) is equivalent to std::aCos(0.5f * r1 * oneOverR) - std::acos(0.5 * r2 * oneOverR) mPhiCuts[iLayer] = std::min(o2::gpu::CAMath::ASin(0.5f * x * oneOverR) + 2.f * mMSangles[iLayer] + delta, o2::constants::math::PI * 0.5f); } } From 98820e9b681677c61f1acac3e5f768cb806eb319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ku=C4=8Dera?= <26327373+vkucera@users.noreply.github.com> Date: Thu, 19 Feb 2026 11:53:32 +0100 Subject: [PATCH 220/234] EMCAL: Delete unused files (#15026) --- .../DataFormatsEMCAL/EMCALChannelData.h | 55 ------ .../Detectors/EMCAL/src/EMCALChannelData.cxx | 19 -- .../reconstruction/run/rawReaderTRUDigits.cxx | 171 ------------------ 3 files changed, 245 deletions(-) delete mode 100644 DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EMCALChannelData.h delete mode 100644 DataFormats/Detectors/EMCAL/src/EMCALChannelData.cxx delete mode 100644 Detectors/EMCAL/reconstruction/run/rawReaderTRUDigits.cxx diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EMCALChannelData.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EMCALChannelData.h deleted file mode 100644 index 3c014d37e6f9e..0000000000000 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EMCALChannelData.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file EMCALChannelData.h -/// \brief - -/// \class EMCALChannelCalibrator -/// \brief Class to store the data format for calibraton of the EMCal -/// \author Hannah Bossi, Yale University -/// \ingroup DetectorEMCAL -/// \since Feb 11, 2021 - -#ifndef ALICEO2_EMCALCHANNELDATA_H -#define ALICEO2_EMCALCHANNELDATA_H - -#include "Rtypes.h" - -namespace o2 -{ -namespace dataformats -{ -class EMCALChannelData -{ - public: - EMCALChannelData(int cellID, int timestamp, int flags = 0, int events) : mEMCALCellID(cellID), mTimestamp(timestamp), mFlags(flags){}; - EMCALChannelData() = default; - ~EMCALChannelData() = default; - - void setEMCALCellID(int index) { mEMCALCellID = index; } - int getEMCALCellID() const { return mEMCALCellID; } - - void setTimestamp(int ts) { mTimestamp = ts; } - int getTimestamp() const { return mTimestamp; } - - void setFlags(int flags) { mFlags = flags; } - float getFlags() const { return mFlags; } - - private: - int mEMCALCellID; ///< EMCal Cell ID - int mTimestamp; ///< timestamp in seconds - unsigned char mFlags; ///< bit mask with quality flags (to be defined) - - ClassDefNV(EMCALChannelData, 1); -}; -} // namespace dataformats -} // namespace o2 -#endif diff --git a/DataFormats/Detectors/EMCAL/src/EMCALChannelData.cxx b/DataFormats/Detectors/EMCAL/src/EMCALChannelData.cxx deleted file mode 100644 index 8affa29259f7a..0000000000000 --- a/DataFormats/Detectors/EMCAL/src/EMCALChannelData.cxx +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file EMCALChannelData.cxx -/// \brief Class to store the data format for calibraton of the EMCal - -#include "DataFormatsEMCAL/EMCALChannelData.h" - -using namespace o2::dataformats; - -ClassImp(o2::dataformats::EMCALChannelData; diff --git a/Detectors/EMCAL/reconstruction/run/rawReaderTRUDigits.cxx b/Detectors/EMCAL/reconstruction/run/rawReaderTRUDigits.cxx deleted file mode 100644 index 6fc119dc69521..0000000000000 --- a/Detectors/EMCAL/reconstruction/run/rawReaderTRUDigits.cxx +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file rawReaderFileNew.cxx -/// \author Markus Fasel , Oak Ridge National Laboratory - -#include -#include - -#include - -#include "DetectorsRaw/RawFileReader.h" -#include "DetectorsRaw/RDHUtils.h" -#include "EMCALBase/Mapper.h" -#include "EMCALBase/TriggerMappingV2.h" -#include "EMCALReconstruction/AltroDecoder.h" -#include "EMCALReconstruction/RawReaderMemory.h" -#include - -namespace bpo = boost::program_options; -// using namespace o2::emcal; - -int main(int argc, char** argv) -{ - bpo::variables_map vm; - bpo::options_description opt_general("Usage:\n " + std::string(argv[0]) + - " \n" - " Tool will decode the DDLx data for EMCAL 0\n" - "Commands / Options"); - bpo::options_description opt_hidden(""); - bpo::options_description opt_all; - bpo::positional_options_description opt_pos; - - try { - auto add_option = opt_general.add_options(); - add_option("help,h", "Print this help message"); - add_option("verbose,v", bpo::value()->default_value(0), "Select verbosity level [0 = no output]"); - add_option("version", "Print version information"); - add_option("input-file,i", bpo::value()->required(), "Specifies input file."); - add_option("debug,d", bpo::value()->default_value(0), "Select debug output level [0 = no debug output]"); - - opt_all.add(opt_general).add(opt_hidden); - bpo::store(bpo::command_line_parser(argc, argv).options(opt_all).positional(opt_pos).run(), vm); - - if (vm.count("help") || argc == 1) { - std::cout << opt_general << std::endl; - exit(0); - } - - if (vm.count("version")) { - // std::cout << GitInfo(); - exit(0); - } - - bpo::notify(vm); - } catch (bpo::error& e) { - std::cerr << "ERROR: " << e.what() << std::endl - << std::endl; - std::cerr << opt_general << std::endl; - exit(1); - } catch (std::exception& e) { - std::cerr << e.what() << ", application will now exit" << std::endl; - exit(2); - } - - auto rawfilename = vm["input-file"].as(); - - o2::raw::RawFileReader reader; - reader.setDefaultDataOrigin(o2::header::gDataOriginEMC); - reader.setDefaultDataDescription(o2::header::gDataDescriptionRawData); - reader.setDefaultReadoutCardType(o2::raw::RawFileReader::RORC); - reader.addFile(rawfilename); - reader.init(); - - o2::emcal::MappingHandler mapper; - o2::emcal::TriggerMappingV2 triggermapping; - - std::unique_ptr treefile(TFile::Open("trudata.root", "RECREATE")); - TTree trudata("trudata", "Tree with TRU data"); - // branches in tree - struct collisiontrigger { - unsigned long bc; - unsigned long orbit; - } mycollision; - int absFastOR; - int starttime; - std::vector timesamples; - tree->Branch(&mycollision, "collisiontrigger", "bc,orbit/l"); - tree->Branch(&starttime, "starttime", "starttime/i"); - tree->Branch(×amples, "timesamples", ""); // @todo check how to write std::vector to tree; - - while (1) { - int tfID = reader.getNextTFToRead(); - if (tfID >= reader.getNTimeFrames()) { - LOG(info) << "nothing left to read after " << tfID << " TFs read"; - break; - } - std::vector dataBuffer; // where to put extracted data - for (int il = 0; il < reader.getNLinks(); il++) { - auto& link = reader.getLink(il); - std::cout << "Decoding link " << il << std::endl; - - auto sz = link.getNextTFSize(); // size in bytes needed for the next TF of this link - dataBuffer.resize(sz); - link.readNextTF(dataBuffer.data()); - - // Parse - o2::emcal::RawReaderMemory parser(dataBuffer); - while (parser.hasNext()) { - parser.next(); - auto rdh = parser.getRawHeader(); - auto ddl = o2::raw::RDHUtils::getFEEID(parser.getRawHeader()); - // Exclude STU DDLs - if (ddl >= 40) { - continue; - } - - mycollision.bc = o2::raw::RDHUtils::getTriggerBC(rdh); - mycollision.orbit = o2::raw::RDHUtils::getTriggerOrbit(rdh); - - o2::emcal::AltroDecoder decoder(parser); - decoder.decode(); - auto& ddlmapping = mapper.getMappingForDDL(ddl); - - std::cout << decoder.getRCUTrailer() << std::endl; - for (auto& chan : decoder.getChannels()) { - if (ddlmapping.getChannelType(chan.getHardwareAddress) != o2::emcal::ChannelType_t::TRU) { - continue; - } - std::cout << "Hw address: " << chan.getHardwareAddress() << std::endl; - // Get absolute FastOR index - this will tell us where on the EMCAL surface the FastOR is - // TRU index is encoded in column, needs to be converted to an absoluted FastOR ID via the - // trigger mapping. The absoluted FastOR ID can be connected via the geometry to tower IDs - // from the FEC data. - // we are only interested in the FastORs for now, skip patches starting from 96 - auto fastorInTRU = ddlmapping.getColumn(chan.getHardwareAddress()); - if (fastorInTRU >= 96) { - // indices starting from 96 encode patches, not FastORs - continue; - } - auto truindex = triggermapping.getTRUIndexFromOnlineHardareAddree(chan.getHardwareAddress(), ddl, ddl / 2); - auto absFastOrID = triggermapping.getAbsFastORIndexFromIndexInTRU(truindex, fastorInTRU); - - for (auto& bunch : chan.getBunches()) { - std::cout << "BunchLength: " << int(bunch.getBunchLength()) << std::endl; - auto adcs = bunch.getADC(); - int time = bunch.getStartTime(); - starttime = time; - timesamples.clear(); - timesamples.resize(adcs.size()); - std::copy(adcs.begin(), adcs.end(), timesamples.begin()); - trudata.Fill(); - for (int i = adcs.size() - 1; i >= 0; i--) { - std::cout << "Timebin " << time << ", ADC " << adcs[i] << std::endl; - time--; - } - } - } - } - } - reader.setNextTFToRead(++tfID); - } -} \ No newline at end of file From 7b4f8f168ca7051f84d73b9ade285882c048348e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ku=C4=8Dera?= <26327373+vkucera@users.noreply.github.com> Date: Thu, 19 Feb 2026 10:14:24 +0100 Subject: [PATCH 221/234] TPC: Delete unused files --- .../TPCReconstruction/ClusterContainer.h | 65 ------------------- .../src/time-series-merge-integrator.cxx | 34 ---------- .../TPC/workflow/src/time-series-reader.cxx | 25 ------- 3 files changed, 124 deletions(-) delete mode 100644 Detectors/TPC/reconstruction/include/TPCReconstruction/ClusterContainer.h delete mode 100644 Detectors/TPC/workflow/src/time-series-merge-integrator.cxx delete mode 100644 Detectors/TPC/workflow/src/time-series-reader.cxx diff --git a/Detectors/TPC/reconstruction/include/TPCReconstruction/ClusterContainer.h b/Detectors/TPC/reconstruction/include/TPCReconstruction/ClusterContainer.h deleted file mode 100644 index d86a845b0fe4c..0000000000000 --- a/Detectors/TPC/reconstruction/include/TPCReconstruction/ClusterContainer.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ClusterContainer.h -/// \brief Container class for TPC clusters -#ifndef _ALICEO2_TPC_ClusterContainer_ -#define _ALICEO2_TPC_ClusterContainer_ - -#include -#include -#include // for Float_t etc - -namespace o2 -{ -namespace tpc -{ - -/// \class ClusterContainer -/// \brief Container class for TPC clusters -class ClusterContainer -{ - public: - // Initialize the clones array - // @param clusterType Possibility to store different types of clusters - // void InitArray(const Char_t* clusterType="o2::tpc::Cluster"); - - /// Add cluster to array - /// @param output, the vector to append to - /// @param cru CRU (sector) - /// @param row Row - /// @param q Total charge of cluster - /// @param qmax Maximum charge in a single cell (pad, time) - /// @param padmean Mean position of cluster in pad direction - /// @param padsigma Sigma of cluster in pad direction - /// @param timemean Mean position of cluster in time direction - /// @param timesigma Sigma of cluster in time direction - template - static ClusterType* addCluster(std::vector* output, - Int_t cru, Int_t row, Float_t qTot, Float_t qMax, - Float_t meanpad, Float_t meantime, Float_t sigmapad, - Float_t sigmatime) - { - assert(output); - output->emplace_back(); // emplace_back a defaut constructed cluster of type ClusterType - auto& cluster = output->back(); - // set its concrete parameters: - // ATTENTION: the order of parameters in setParameters is different than in AddCluster! - cluster.setParameters(cru, row, qTot, qMax, - meanpad, sigmapad, - meantime, sigmatime); - return &cluster; - } -}; -} // namespace tpc -} // namespace o2 - -#endif diff --git a/Detectors/TPC/workflow/src/time-series-merge-integrator.cxx b/Detectors/TPC/workflow/src/time-series-merge-integrator.cxx deleted file mode 100644 index c17b68e307328..0000000000000 --- a/Detectors/TPC/workflow/src/time-series-merge-integrator.cxx +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "TPCWorkflow/TPCMergeTimeSeriesSpec.h" -#include "CommonUtils/ConfigurableParam.h" -#include "Framework/ConfigParamSpec.h" - -using namespace o2::framework; - -void customize(std::vector& workflowOptions) -{ - std::vector options{ - ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, - }; - std::swap(workflowOptions, options); -} - -#include "Framework/runDataProcessing.h" - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec wf; - o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); - wf.emplace_back(o2::tpc::getTPCMergeTimeSeriesSpec()); - return wf; -} diff --git a/Detectors/TPC/workflow/src/time-series-reader.cxx b/Detectors/TPC/workflow/src/time-series-reader.cxx deleted file mode 100644 index ccedbdf4f9599..0000000000000 --- a/Detectors/TPC/workflow/src/time-series-reader.cxx +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "TPCWorkflow/TPCTimeSeriesReaderSpec.h" -#include "CommonUtils/ConfigurableParam.h" -#include "Framework/ConfigParamSpec.h" - -using namespace o2::framework; - -#include "Framework/runDataProcessing.h" - -WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) -{ - WorkflowSpec wf; - wf.emplace_back(o2::tpc::getTPCTimeSeriesReaderSpec()); - return wf; -} From 1d4b3ef48aef20e6866379301de6e9d94ff234c2 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 17 Feb 2026 22:15:26 +0100 Subject: [PATCH 222/234] DPL: add ability to get the toplevel service registry This will allows non DPL code to still exploit some of the DPL services, like monitoring. --- Framework/Core/CMakeLists.txt | 1 + .../include/Framework/ServiceRegistryRef.h | 2 ++ Framework/Core/src/ServiceRegistryRef.cxx | 25 +++++++++++++++++++ Framework/Core/src/runDataProcessing.cxx | 1 + 4 files changed, 29 insertions(+) create mode 100644 Framework/Core/src/ServiceRegistryRef.cxx diff --git a/Framework/Core/CMakeLists.txt b/Framework/Core/CMakeLists.txt index 7357167a3fcd8..e6a8db1077136 100644 --- a/Framework/Core/CMakeLists.txt +++ b/Framework/Core/CMakeLists.txt @@ -125,6 +125,7 @@ o2_add_library(Framework src/RootArrowFilesystem.cxx src/SendingPolicy.cxx src/ServiceRegistry.cxx + src/ServiceRegistryRef.cxx src/ServiceSpec.cxx src/SimpleResourceManager.cxx src/SimpleRawDeviceService.cxx diff --git a/Framework/Core/include/Framework/ServiceRegistryRef.h b/Framework/Core/include/Framework/ServiceRegistryRef.h index 910d4e726c080..85aad6d70e93b 100644 --- a/Framework/Core/include/Framework/ServiceRegistryRef.h +++ b/Framework/Core/include/Framework/ServiceRegistryRef.h @@ -112,6 +112,8 @@ class ServiceRegistryRef mRegistry.unlock(mSalt); } + static ServiceRegistryRef *globalDeviceRef(ServiceRegistryRef *ref = nullptr); + private: ServiceRegistry& mRegistry; ServiceRegistry::Salt mSalt; diff --git a/Framework/Core/src/ServiceRegistryRef.cxx b/Framework/Core/src/ServiceRegistryRef.cxx new file mode 100644 index 0000000000000..70728ad37eda7 --- /dev/null +++ b/Framework/Core/src/ServiceRegistryRef.cxx @@ -0,0 +1,25 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + + +#include "Framework/ServiceRegistryRef.h" +namespace o2::framework { + +ServiceRegistryRef *ServiceRegistryRef::globalDeviceRef(ServiceRegistryRef *ref) { + static ServiceRegistryRef *globalRef = nullptr; + if (!globalRef) { + globalRef = ref; + } + // We return a copy, so that it can be cache + return globalRef; +} + +} diff --git a/Framework/Core/src/runDataProcessing.cxx b/Framework/Core/src/runDataProcessing.cxx index ced884ebaa1ed..b99b5119e3ce9 100644 --- a/Framework/Core/src/runDataProcessing.cxx +++ b/Framework/Core/src/runDataProcessing.cxx @@ -1429,6 +1429,7 @@ int runStateMachine(DataProcessorSpecs const& workflow, // We initialise this in the driver, because different drivers might have // different versions of the service ServiceRegistry serviceRegistry; + ServiceRegistryRef::globalDeviceRef(new ServiceRegistryRef{serviceRegistry, ServiceRegistry::globalDeviceSalt()}); if ((driverConfig.batch == false || getenv("DPL_DRIVER_REMOTE_GUI") != nullptr) && frameworkId.empty()) { debugGUI = initDebugGUI(); From 813e416361a029fa023fd3fa6116cbb54a700bba Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 17 Feb 2026 22:15:26 +0100 Subject: [PATCH 223/234] CCDB: report stats about CCDB fetches / misses to DPL --- CCDB/include/CCDB/BasicCCDBManager.h | 11 ++++++++- CCDB/src/BasicCCDBManager.cxx | 2 ++ .../include/Framework/DataProcessingStats.h | 3 +++ Framework/Core/src/CommonServices.cxx | 24 +++++++++++++++++++ Framework/Core/src/runDataProcessing.cxx | 1 + 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/CCDB/include/CCDB/BasicCCDBManager.h b/CCDB/include/CCDB/BasicCCDBManager.h index 71287c2f07d76..fd0fe7aa6d05b 100644 --- a/CCDB/include/CCDB/BasicCCDBManager.h +++ b/CCDB/include/CCDB/BasicCCDBManager.h @@ -20,6 +20,8 @@ #include "CommonUtils/NameConf.h" #include "Framework/DataTakingContext.h" #include "Framework/DefaultsHelpers.h" +#include "Framework/ServiceRegistryRef.h" +#include "Framework/DataProcessingStats.h" #include #include #include @@ -340,6 +342,13 @@ T* CCDBManagerInstance::getForTimeStamp(std::string const& path, long timestamp, } auto end = std::chrono::system_clock::now(); mTimerMS += std::chrono::duration_cast(end - start).count(); + auto *ref = o2::framework::ServiceRegistryRef::globalDeviceRef(); + if (ref && ref->active()) { + auto& stats = ref->get(); + stats.updateStats({(int)o2::framework::ProcessingStatsId::CCDB_CACHE_HIT, o2::framework::DataProcessingStats::Op::Set, (int64_t)mQueries - mFailures - mFetches}); + stats.updateStats({(int)o2::framework::ProcessingStatsId::CCDB_CACHE_MISS, o2::framework::DataProcessingStats::Op::Set, (int64_t)mFetches}); + stats.updateStats({(int)o2::framework::ProcessingStatsId::CCDB_CACHE_FAILURE, o2::framework::DataProcessingStats::Op::Set, (int64_t)mFailures}); + } return ptr; } @@ -391,4 +400,4 @@ class BasicCCDBManager : public CCDBManagerInstance } // namespace o2::ccdb -#endif //O2_BASICCCDBMANAGER_H +#endif // O2_BASICCCDBMANAGER_H diff --git a/CCDB/src/BasicCCDBManager.cxx b/CCDB/src/BasicCCDBManager.cxx index bcf88554578c1..d55fdad960d3a 100644 --- a/CCDB/src/BasicCCDBManager.cxx +++ b/CCDB/src/BasicCCDBManager.cxx @@ -13,6 +13,8 @@ // Created by Sandro Wenzel on 2019-08-14. // #include "CCDB/BasicCCDBManager.h" +#include "Framework/ServiceRegistryRef.h" +#include "Framework/DataProcessingStats.h" #include #include #include diff --git a/Framework/Core/include/Framework/DataProcessingStats.h b/Framework/Core/include/Framework/DataProcessingStats.h index e32523c9abb08..a1f5c0eec5568 100644 --- a/Framework/Core/include/Framework/DataProcessingStats.h +++ b/Framework/Core/include/Framework/DataProcessingStats.h @@ -69,6 +69,9 @@ enum struct ProcessingStatsId : short { RESOURCES_MISSING, RESOURCES_INSUFFICIENT, RESOURCES_SATISFACTORY, + CCDB_CACHE_HIT, + CCDB_CACHE_MISS, + CCDB_CACHE_FAILURE, AVAILABLE_MANAGED_SHM_BASE = 512, }; diff --git a/Framework/Core/src/CommonServices.cxx b/Framework/Core/src/CommonServices.cxx index 6486406a06dca..06bc7969ebf1e 100644 --- a/Framework/Core/src/CommonServices.cxx +++ b/Framework/Core/src/CommonServices.cxx @@ -1152,6 +1152,30 @@ o2::framework::ServiceSpec CommonServices::dataProcessingStats() .scope = Scope::DPL, .minPublishInterval = 0, .maxRefreshLatency = 10000, + .sendInitialValue = true}, + MetricSpec{.name = "ccdb-cache-hit", + .enabled = true, + .metricId = static_cast(ProcessingStatsId::CCDB_CACHE_HIT), + .kind = Kind::UInt64, + .scope = Scope::DPL, + .minPublishInterval = 1000, + .maxRefreshLatency = 10000, + .sendInitialValue = true}, + MetricSpec{.name = "ccdb-cache-miss", + .enabled = true, + .metricId = static_cast(ProcessingStatsId::CCDB_CACHE_MISS), + .kind = Kind::UInt64, + .scope = Scope::DPL, + .minPublishInterval = 1000, + .maxRefreshLatency = 10000, + .sendInitialValue = true}, + MetricSpec{.name = "ccdb-cache-failure", + .enabled = true, + .metricId = static_cast(ProcessingStatsId::CCDB_CACHE_FAILURE), + .kind = Kind::UInt64, + .scope = Scope::DPL, + .minPublishInterval = 1000, + .maxRefreshLatency = 10000, .sendInitialValue = true}}; for (auto& metric : metrics) { diff --git a/Framework/Core/src/runDataProcessing.cxx b/Framework/Core/src/runDataProcessing.cxx index b99b5119e3ce9..815fce47544d0 100644 --- a/Framework/Core/src/runDataProcessing.cxx +++ b/Framework/Core/src/runDataProcessing.cxx @@ -1248,6 +1248,7 @@ std::vector getDumpableMetrics() dumpableMetrics.emplace_back("^total-timeframes.*"); dumpableMetrics.emplace_back("^device_state.*"); dumpableMetrics.emplace_back("^total_wall_time_ms$"); + dumpableMetrics.emplace_back("^ccdb-.*$"); return dumpableMetrics; } From d569998f2457c1eb4f35596b38cf9a4c4bea23a5 Mon Sep 17 00:00:00 2001 From: Francesco Noferini Date: Wed, 18 Feb 2026 17:20:27 +0100 Subject: [PATCH 224/234] path for LHCphase ccdb configurable --- .../calibration/include/TOFCalibration/LHCClockCalibrator.h | 3 +++ Detectors/TOF/calibration/src/LHCClockCalibrator.cxx | 2 +- .../TOF/calibration/testWorkflow/LHCClockCalibratorSpec.h | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Detectors/TOF/calibration/include/TOFCalibration/LHCClockCalibrator.h b/Detectors/TOF/calibration/include/TOFCalibration/LHCClockCalibrator.h index aaab8a06e5e86..4c8f5cdae8654 100644 --- a/Detectors/TOF/calibration/include/TOFCalibration/LHCClockCalibrator.h +++ b/Detectors/TOF/calibration/include/TOFCalibration/LHCClockCalibrator.h @@ -99,6 +99,8 @@ class LHCClockCalibrator final : public o2::calibration::TimeSlotCalibration("nbins")); auto slotL = ic.options().get("tf-per-slot"); auto delay = ic.options().get("max-delay"); + std::string path = ic.options().get("output-path"); + mCalibrator = std::make_unique(minEnt, nb); + mCalibrator->setPath(path.data()); mCalibrator->setSlotLength(slotL); mCalibrator->setMaxSlotsDelay(delay); @@ -216,6 +219,7 @@ DataProcessorSpec getLHCClockCalibDeviceSpec(bool useCCDB) AlgorithmSpec{adaptFromTask(ccdbRequest, useCCDB)}, Options{ {"tf-per-slot", VariantType::UInt32, 5u, {"number of TFs per calibration time slot"}}, + {"output-path", VariantType::String, "TOF/Calib/LHCphaseSync", {"path to ccdb output"}}, {"max-delay", VariantType::UInt32, 3u, {"number of slots in past to consider"}}, {"min-entries", VariantType::Int, 500, {"minimum number of entries to fit single time slot"}}, {"nbins", VariantType::Int, 4000, {"number of bins for "}}}}; From 67ab6d5a3922f27ce27376993bf5523b8c5d9e5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ku=C4=8Dera?= <26327373+vkucera@users.noreply.github.com> Date: Thu, 5 Feb 2026 22:44:32 +0100 Subject: [PATCH 225/234] HMPID: Delete unused files --- .../HMPIDReconstruction/HmpidDecodeRawFile.h | 63 - .../HMPIDReconstruction/HmpidDecodeRawMem.h | 73 -- .../reconstruction/src/HmpidDecodeRawFile.cxx | 158 --- .../reconstruction/src/HmpidDecodeRawMem.cxx | 184 --- .../HMPID/reconstruction/src/HmpidDecoder.cxx | 1134 ----------------- .../HMPIDWorkflow/ClusterizerSpec.h_notused.h | 27 - .../HMPIDWorkflow/DigitReaderSpec.h_notused.h | 53 - 7 files changed, 1692 deletions(-) delete mode 100644 Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawFile.h delete mode 100644 Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawMem.h delete mode 100644 Detectors/HMPID/reconstruction/src/HmpidDecodeRawFile.cxx delete mode 100644 Detectors/HMPID/reconstruction/src/HmpidDecodeRawMem.cxx delete mode 100644 Detectors/HMPID/reconstruction/src/HmpidDecoder.cxx delete mode 100644 Detectors/HMPID/workflow/include/HMPIDWorkflow/ClusterizerSpec.h_notused.h delete mode 100644 Detectors/HMPID/workflow/include/HMPIDWorkflow/DigitReaderSpec.h_notused.h diff --git a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawFile.h b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawFile.h deleted file mode 100644 index e92e8375ad0d0..0000000000000 --- a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawFile.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file HmpidDecodeRawFile.h -/// \author Antonio Franco - INFN Bari -/// \brief Derived Class for decoding Raw Data File stream -/// \version 1.0 -/// \date 24 set 2020 - -#ifndef COMMON_HMPIDDECODERAWFILE_H_ -#define COMMON_HMPIDDECODERAWFILE_H_ - -#include -#include -#include -#include -#include -#include - -#include "HMPIDReconstruction/HmpidDecoder.h" - -#define MAXFILENAMEBUFFER 512 -#define MAXRAWFILEBUFFER RAWBLOCKDIMENSION_W * 4 + 8 - -namespace o2 -{ -namespace hmpid -{ - -class HmpidDecodeRawFile : public HmpidDecoder -{ - public: - HmpidDecodeRawFile(int* EqIds, int* CruIds, int* LinkIds, int numOfEquipments); - HmpidDecodeRawFile(int numOfEquipments); - ~HmpidDecodeRawFile(); - - bool setUpStream(void* InpuFileName, long Size); - - private: - bool getBlockFromStream(uint32_t** streamPtr, uint32_t Size); - bool getHeaderFromStream(uint32_t** streamPtr); - bool getWordFromStream(uint32_t* word); - int fileExists(char* filewithpath); - void setPad(HmpidEquipment* eq, int col, int dil, int ch, uint16_t charge); - - private: - FILE* fh; - char mInputFile[MAXFILENAMEBUFFER]; - uint32_t mFileBuffer[MAXRAWFILEBUFFER]; -}; - -} // namespace hmpid -} // namespace o2 -#endif /* COMMON_HMPIDDECODERAWFILE_H_ */ diff --git a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawMem.h b/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawMem.h deleted file mode 100644 index d5d82d0f238e9..0000000000000 --- a/Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawMem.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file HmpidDecodeRawMem.h -/// \author Antonio Franco - INFN Bari -/// \brief Derived Class for decoding Raw Data Memory stream -/// \version 1.0 -/// \date 24 set 2020 - -#ifndef COMMON_HMPIDDECODERAWMEM_H_ -#define COMMON_HMPIDDECODERAWMEM_H_ - -#include -#include -#include -#include -#include -#include - -#include "DataFormatsHMP/Digit.h" -#include "HMPIDBase/Geo.h" -#include "HMPIDReconstruction/HmpidDecoder.h" - -using namespace o2; - -namespace o2 -{ -namespace hmpid -{ - -class HmpidDecodeRawMem : public HmpidDecoder -{ - public: - HmpidDecodeRawMem(int* EqIds, int* CruIds, int* LinkIds, int numOfEquipments); - HmpidDecodeRawMem(int numOfEquipments); - ~HmpidDecodeRawMem(); - - bool setUpStream(void* Buffer, long BufferLen) override; - - private: - bool getBlockFromStream(uint32_t** streamPtr, uint32_t Size) override; - bool getHeaderFromStream(uint32_t** streamPtr) override; - bool getWordFromStream(uint32_t* word) override; - void setPad(HmpidEquipment* eq, int col, int dil, int ch, uint16_t charge) override; - - private: -}; - -class HmpidDecodeRawDigit : public HmpidDecodeRawMem -{ - public: - HmpidDecodeRawDigit(int* EqIds, int* CruIds, int* LinkIds, int numOfEquipments); - HmpidDecodeRawDigit(int numOfEquipments); - ~HmpidDecodeRawDigit(); - - std::vector mDigits; - - private: - void setPad(HmpidEquipment* eq, int col, int dil, int ch, uint16_t charge) override; -}; - -} // namespace hmpid -} // namespace o2 -#endif /* COMMON_HMPIDDECODERAWFILE_H_ */ diff --git a/Detectors/HMPID/reconstruction/src/HmpidDecodeRawFile.cxx b/Detectors/HMPID/reconstruction/src/HmpidDecodeRawFile.cxx deleted file mode 100644 index df97a4d2101e0..0000000000000 --- a/Detectors/HMPID/reconstruction/src/HmpidDecodeRawFile.cxx +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file HmpidDecodeRawFile.cxx -/// \author Antonio Franco - INFN Bari -/// \brief Derived Class for decoding Raw Data File stream -/// \version 1.0 -/// \date 24 set 2020 - -/* ------ HISTORY --------- -*/ -#include // for LOG -#include "Framework/Logger.h" - -#include "HMPIDReconstruction/HmpidDecodeRawFile.h" - -using namespace o2::hmpid; - -/// Constructor with the default HMPID equipments map at P2 -/// @param[in] numOfEquipments : number of defined equipments [0..13] -HmpidDecodeRawFile::HmpidDecodeRawFile(int numOfEquipments) - : HmpidDecoder(numOfEquipments) -{ - fh = 0; -} - -/// Constructor with the HMPID address map -/// @param[in] numOfEquipments : the number of equipments to define [1..14] -/// @param[in] *EqIds : the pointer to the Equipments ID array -/// @param[in] *CruIds : the pointer to the CRU ID array -/// @param[in] *LinkIds : the pointer to the Link ID array -HmpidDecodeRawFile::HmpidDecodeRawFile(int* EqIds, int* CruIds, int* LinkIds, int numOfEquipments) - : HmpidDecoder(EqIds, CruIds, LinkIds, numOfEquipments) -{ - fh = 0; -} - -/// Destructor -HmpidDecodeRawFile::~HmpidDecodeRawFile() -{ -} - -/// Setup the Input Stream with a File Handle -/// verify the existence and try to open it -/// @param[in] *FileName : the string that contains the File Name -/// @param[in] Size : not used -/// @returns True if the file is opened -/// @throws TH_FILENOTEXISTS Thrown if the file doesn't exists -/// @throws TH_OPENFILE Thrown if Fails to open the file -bool HmpidDecodeRawFile::setUpStream(void* FileName, long Size) -{ - strcpy(mInputFile, (const char*)FileName); - // files section ---- - if (!fileExists(mInputFile)) { - LOG(error) << "The input file " << mInputFile << " does not exist at this time."; - throw TH_FILENOTEXISTS; - } - // open the file - fh = fopen(mInputFile, "rb"); - if (fh == 0) { - LOG(error) << "ERROR to open Input file ! [" << mInputFile << "]"; - throw TH_OPENFILE; - } - - mActualStreamPtr = 0; // sets the pointer to the Buffer - mEndStreamPtr = 0; //sets the End of buffer - mStartStreamPtr = 0; - - return (true); -} - -/// Gets a sized chunk from the stream. Read from the file and update the pointers -/// ATTENTION : in order to optimize the disk accesses the block read pre-load a -/// complete Header+Payload block, the Size parameter is recalculated with the -/// dimension of the pack extract from the header field 'Offeset' -/// -/// verify the existence and try to open it -/// @param[in] **streamPtr : the pointer to the memory buffer -/// @param[in] Size : not used -/// @returns True if the file is opened -/// @throws TH_WRONGFILELEN Thrown if the file doesn't contains enough words -bool HmpidDecodeRawFile::getBlockFromStream(uint32_t** streamPtr, uint32_t Size) -{ - if (Size > MAXRAWFILEBUFFER) - return (false); - int nr = fread(mFileBuffer, sizeof(int32_t), HEADERDIMENSION_W, fh); - if (nr != HEADERDIMENSION_W) { - throw TH_WRONGFILELEN; - } - Size = ((mFileBuffer[2] & 0x0000FFFF) / sizeof(int32_t)) - HEADERDIMENSION_W; - nr = fread(mFileBuffer + HEADERDIMENSION_W, sizeof(int32_t), Size, fh); - LOG(debug) << " getBlockFromStream read " << nr << " of " << Size + HEADERDIMENSION_W << " words !"; - if (nr != Size) { - throw TH_WRONGFILELEN; - } - *streamPtr = mFileBuffer; - mStartStreamPtr = mFileBuffer; - mActualStreamPtr = mFileBuffer; - mEndStreamPtr = mFileBuffer + Size; - return (true); -} - -/// Reads the Header from the file -/// @param[in] **streamPtr : the pointer to the memory buffer -/// @returns True if the header is read -bool HmpidDecodeRawFile::getHeaderFromStream(uint32_t** streamPtr) -{ - bool flag = getBlockFromStream(streamPtr, RAWBLOCKDIMENSION_W); // reads the 8k block - mActualStreamPtr += HEADERDIMENSION_W; // Move forward for the first word - return (flag); -} - -/// Read one word from the pre-load buffer -/// @param[in] *word : the buffer for the read word -/// @returns True every time -bool HmpidDecodeRawFile::getWordFromStream(uint32_t* word) -{ - *word = *mActualStreamPtr; - mActualStreamPtr++; - return (true); -} - -/// ----- Sets the Pad ! ------ -/// this is an overloaded method. In this version the value of the charge -/// is used to update the statistical matrix of the base class -/// -/// @param[in] *eq : the pointer to the Equipment object -/// @param[in] col : the column [0..23] -/// @param[in] dil : the dilogic [0..9] -/// @param[in] ch : the channel [0..47] -/// @param[in] charge : the value of the charge -void HmpidDecodeRawFile::setPad(HmpidEquipment* eq, int col, int dil, int ch, uint16_t charge) -{ - eq->setPad(col, dil, ch, charge); - return; -} - -/// Checks if the file exists ! -/// @param[in] *filewithpath : the File Name to check -/// @returns True if the file exists -int HmpidDecodeRawFile::fileExists(char* filewithpath) -{ - if (access(filewithpath, F_OK) != -1) { - return (true); - } else { - return (false); - } -} -o2::hmpid::Digit diff --git a/Detectors/HMPID/reconstruction/src/HmpidDecodeRawMem.cxx b/Detectors/HMPID/reconstruction/src/HmpidDecodeRawMem.cxx deleted file mode 100644 index 5a4f2acbfd97b..0000000000000 --- a/Detectors/HMPID/reconstruction/src/HmpidDecodeRawMem.cxx +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// -/// \file HmpidDecodeRawMem.cxx -/// \author Antonio Franco - INFN Bari -/// \brief Derived Class for decoding Raw Data Memory stream -/// \version 1.0 -/// \date 24 set 2020 - -/* ------ HISTORY --------- -*/ -#include // for LOG -#include "Framework/Logger.h" - -#include "DataFormatsHMP/Digit.h" -#include "HMPIDBase/Geo.h" -#include "HMPIDReconstruction/HmpidDecodeRawMem.h" - -using namespace o2::hmpid; - -/// Constructor : accepts the number of equipments to define -/// The mapping is the default at P2 -/// Allocates instances for all defined equipments -/// normally it is equal to 14 -/// @param[in] numOfEquipments : the number of equipments to define [1..14] -HmpidDecodeRawMem::HmpidDecodeRawMem(int numOfEquipments) - : HmpidDecoder(numOfEquipments) -{ -} - -/// Constructor : accepts the number of equipments to define -/// and their complete address map -/// Allocates instances for all defined equipments -/// -/// The Address map is build from three array -/// @param[in] numOfEquipments : the number of equipments to define [1..14] -/// @param[in] *EqIds : the pointer to the Equipments ID array -/// @param[in] *CruIds : the pointer to the CRU ID array -/// @param[in] *LinkIds : the pointer to the Link ID array -HmpidDecodeRawMem::HmpidDecodeRawMem(int* EqIds, int* CruIds, int* LinkIds, int numOfEquipments) - : HmpidDecoder(EqIds, CruIds, LinkIds, numOfEquipments) -{ -} - -/// Destructor -HmpidDecodeRawMem::~HmpidDecodeRawMem() = default; - -/// Setup the Input Stream with a Memory Pointer -/// the buffer length is in byte, some controls are done -/// -/// @param[in] *Buffer : the pointer to Memory buffer -/// @param[in] BufferLen : the length of the buffer (bytes) -/// @returns True if the stream is set -/// @throws TH_NULLBUFFERPOINTER Thrown if the pointer to the buffer is NULL -/// @throws TH_BUFFEREMPTY Thrown if the buffer is empty -/// @throws TH_WRONGBUFFERDIM Thrown if the buffer len is less then one header -bool HmpidDecodeRawMem::setUpStream(void* Buffer, long BufferLen) -{ - long wordsBufferLen = BufferLen / (sizeof(int32_t) / sizeof(char)); // Converts the len in words - if (Buffer == nullptr) { - LOG(error) << "Raw data buffer null Pointer ! "; - throw TH_NULLBUFFERPOINTER; - } - if (wordsBufferLen == 0) { - LOG(error) << "Raw data buffer Empty ! "; - throw TH_BUFFEREMPTY; - } - if (wordsBufferLen < 16) { - LOG(error) << "Raw data buffer less then the Header Dimension = " << wordsBufferLen; - throw TH_WRONGBUFFERDIM; - } - - mActualStreamPtr = (uint32_t*)Buffer; // sets the pointer to the Buffer - mEndStreamPtr = ((uint32_t*)Buffer) + wordsBufferLen; //sets the End of buffer - mStartStreamPtr = ((uint32_t*)Buffer); - // std::cout << " setUpStrem : StPtr=" << mStartStreamPtr << " EndPtr=" << mEndStreamPtr << " Len=" << wordsBufferLen << std::endl; - return (true); -} - -/// Gets a sized chunk from the stream. The stream pointers members are updated -/// @param[in] **streamPtr : the pointer to the memory buffer -/// @param[in] Size : the dimension of the chunk (words) -/// @returns True every time -/// @throw TH_WRONGBUFFERDIM Buffer length shorter then the requested -bool HmpidDecodeRawMem::getBlockFromStream(uint32_t** streamPtr, uint32_t Size) -{ - *streamPtr = mActualStreamPtr; - mActualStreamPtr += Size; - if (mActualStreamPtr > mEndStreamPtr) { - // std::cout << " getBlockFromStream : StPtr=" << mActualStreamPtr << " EndPtr=" << mEndStreamPtr << " Len=" << Size << std::endl; - // std::cout << "Beccato " << std::endl; - // throw TH_WRONGBUFFERDIM; - return (false); - } - return (true); -} - -/// Gets the Header Block from the stream. -/// @param[in] **streamPtr : the pointer to the memory buffer -/// @returns True if the header is read -bool HmpidDecodeRawMem::getHeaderFromStream(uint32_t** streamPtr) -{ - return (getBlockFromStream(streamPtr, mRDHSize)); -} - -/// Gets a Word from the stream. -/// @param[in] *word : the buffer for the read word -/// @returns True if the operation end well -bool HmpidDecodeRawMem::getWordFromStream(uint32_t* word) -{ - uint32_t* appo; - *word = *mActualStreamPtr; - return (getBlockFromStream(&appo, 1)); -} - -/// ----- Sets the Pad ! ------ -/// this is an overloaded method. In this version the value of the charge -/// is used to update the statistical matrix of the base class -/// -/// @param[in] *eq : the pointer to the Equipment object -/// @param[in] col : the column [0..23] -/// @param[in] dil : the dilogic [0..9] -/// @param[in] ch : the channel [0..47] -/// @param[in] charge : the value of the charge -void HmpidDecodeRawMem::setPad(HmpidEquipment* eq, int col, int dil, int ch, uint16_t charge) -{ - eq->setPad(col, dil, ch, charge); - return; -} - -// ======================================================================================== - -/// Constructor : accepts the number of equipments to define -/// The mapping is the default at P2 -/// Allocates instances for all defined equipments -/// normally it is equal to 14 -/// @param[in] numOfEquipments : the number of equipments to define [1..14] -HmpidDecodeRawDigit::HmpidDecodeRawDigit(int numOfEquipments) - : HmpidDecodeRawMem(numOfEquipments) -{ -} - -/// Constructor : accepts the number of equipments to define -/// and their complete address map -/// Allocates instances for all defined equipments -/// -/// The Address map is build from three array -/// @param[in] numOfEquipments : the number of equipments to define [1..14] -/// @param[in] *EqIds : the pointer to the Equipments ID array -/// @param[in] *CruIds : the pointer to the CRU ID array -/// @param[in] *LinkIds : the pointer to the Link ID array -HmpidDecodeRawDigit::HmpidDecodeRawDigit(int* EqIds, int* CruIds, int* LinkIds, int numOfEquipments) - : HmpidDecodeRawMem(EqIds, CruIds, LinkIds, numOfEquipments) -{ -} - -/// Destructor -HmpidDecodeRawDigit::~HmpidDecodeRawDigit() = default; - -/// ----- Sets the Pad ! ------ -/// this is an overloaded method. In this version the value of the charge -/// is used to update the statistical matrix of the base class -/// -/// @param[in] *eq : the pointer to the Equipment object -/// @param[in] col : the column [0..23] -/// @param[in] dil : the dilogic [0..9] -/// @param[in] ch : the channel [0..47] -/// @param[in] charge : the value of the charge -void HmpidDecodeRawDigit::setPad(HmpidEquipment* eq, int col, int dil, int ch, uint16_t charge) -{ - eq->setPad(col, dil, ch, charge); - mDigits.push_back(o2::hmpid::Digit(charge, eq->getEquipmentId(), col, dil, ch)); - //std::cout << "DI " << mDigits.back() << " "< // for LOG -#include "Framework/Logger.h" -#include "Headers/RAWDataHeader.h" -#include "HMPIDReconstruction/HmpidDecoder.h" -#include "DataFormatsHMP/Digit.h" - -using namespace o2::hmpid; - -// ============= HmpidDecoder Class implementation ======= - -/// Decoding Error Messages Definitions -char HmpidDecoder::sErrorDescription[MAXERRORS][MAXDESCRIPTIONLENGHT] = {"Word that I don't known !", - "Row Marker Word with 0 words", "Duplicated Pad Word !", "Row Marker Wrong/Lost -> to EoE", - "Row Marker Wrong/Lost -> to EoE", "Row Marker reports an ERROR !", "Lost EoE Marker !", "Double EoE marker", - "Wrong size definition in EoE Marker", "Double Mark Word", "Wrong Size in Segment Marker", "Lost EoS Marker !", - "HMPID Header Errors"}; - -/// HMPID Firmware Error Messages Definitions -char HmpidDecoder::sHmpidErrorDescription[MAXHMPIDERRORS][MAXDESCRIPTIONLENGHT] = { - "L0 Missing," - "L1 is received without L0", - "L1A signal arrived before the L1 Latency", "L1A signal arrived after the L1 Latency", - "L1A is missing or L1 timeout", "L1A Message is missing or L1 Message"}; - -/// Constructor : accepts the number of equipments to define -/// The mapping is the default at P2 -/// Allocates instances for all defined equipments -/// normally it is equal to 14 -/// @param[in] numOfEquipments : the number of equipments to define [1..14] -HmpidDecoder::HmpidDecoder(int numOfEquipments) -{ - // The standard definition of HMPID equipments at P2 - int EqIds[] = {0, 1, 2, 3, 4, 5, 8, 9, 6, 7, 10, 11, 12, 13}; - int CruIds[] = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3}; - int LinkIds[] = {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 0, 1, 2}; - - mNumberOfEquipments = numOfEquipments; - for (int i = 0; i < mNumberOfEquipments; i++) { - mTheEquipments[i] = new HmpidEquipment(EqIds[i], CruIds[i], LinkIds[i]); - } -} - -/// Constructor : accepts the number of equipments to define -/// and their complete address map -/// Allocates instances for all defined equipments -/// -/// The Address map is build from three array -/// @param[in] numOfEquipments : the number of equipments to define [1..14] -/// @param[in] *EqIds : the pointer to the Equipments ID array -/// @param[in] *CruIds : the pointer to the CRU ID array -/// @param[in] *LinkIds : the pointer to the Link ID array -HmpidDecoder::HmpidDecoder(int* EqIds, int* CruIds, int* LinkIds, int numOfEquipments) -{ - mNumberOfEquipments = numOfEquipments; - for (int i = 0; i < mNumberOfEquipments; i++) { - mTheEquipments[i] = new HmpidEquipment(EqIds[i], CruIds[i], LinkIds[i]); - } -} - -/// Destructor : remove the Equipments instances -HmpidDecoder::~HmpidDecoder() -{ - for (int i = 0; i < mNumberOfEquipments; i++) { - delete mTheEquipments[i]; - } -} - -/// Init all the members variables. -void HmpidDecoder::init() -{ - mRDHSize = sizeof(o2::header::RAWDataHeader) / sizeof(uint32_t); - - mVerbose = 0; - mHeEvent = 0; - mHeBusy = 0; - mNumberWordToRead = 0; - mPayloadTail = 0; - - mHeFEEID = 0; - mHeSize = 0; - mHeVer = 0; - mHePrior = 0; - mHeStop = 0; - mHePages = 0; - mEquipment = 0; - - mHeOffsetNewPack = 0; - mHeMemorySize = 0; - - mHeDetectorID = 0; - mHeDW = 0; - mHeCruID = 0; - mHePackNum = 0; - mHePAR = 0; - mHePageNum = 0; - mHeLinkNum = 0; - mHeFirmwareVersion = 0; - mHeHmpidError = 0; - mHeBCDI = 0; - mHeORBIT = 0; - mHeTType = 0; - - mActualStreamPtr = nullptr; - mEndStreamPtr = nullptr; - mStartStreamPtr = nullptr; - - for (int i = 0; i < mNumberOfEquipments; i++) { - mTheEquipments[i]->init(); - } -} - -/// Returns the Equipment Index (Pointer of the array) converting -/// the FLP hardware coords (CRU_Id and Link_Id) -/// @param[in] CruId : the CRU ID [0..3] -> FLP 160 = [0,1] FLP 161 = [2,3] -/// @param[in] LinkId : the Link ID [0..3] -/// @returns EquipmentIndex : the index in the Equipment array [0..13] (-1 := error) -int HmpidDecoder::getEquipmentIndex(int CruId, int LinkId) -{ - for (int i = 0; i < mNumberOfEquipments; i++) { - if (mTheEquipments[i]->getEquipmentId(CruId, LinkId) != -1) { - return (i); - } - } - return (-1); -} - -/// Returns the Equipment Index (Pointer of the array) converting -/// the Equipment_ID (Firmaware defined Id AKA FFEID) -/// @param[in] EquipmentId : the Equipment ID [0..13] -/// @returns EquipmentIndex : the index in the Equipment array [0..13] (-1 := error) -int HmpidDecoder::getEquipmentIndex(int EquipmentId) -{ - for (int i = 0; i < mNumberOfEquipments; i++) { - if (mTheEquipments[i]->getEquipmentId() == EquipmentId) { - return (i); - } - } - return (-1); -} - -/// Returns the Equipment_ID converting the FLP hardware coords -/// @param[in] CruId : the CRU ID [0..3] -> FLP 160 = [0,1] FLP 161 = [2,3] -/// @param[in] LinkId : the Link ID [0..3] -/// @returns EquipmentID : the ID of the Equipment [0..13] (-1 := error) -int HmpidDecoder::getEquipmentID(int CruId, int LinkId) -{ - for (int i = 0; i < mNumberOfEquipments; i++) { - if (mTheEquipments[i]->getEquipmentId(CruId, LinkId) != -1) { - return (mTheEquipments[i]->getEquipmentId()); - } - } - return (-1); -} - -/// Scans the BitMap of Raw Data File word and detect the type -/// and the parameters -/// @param[in] wp : the word to analyze -/// @param[out] *p1 : first parameter extract (if it exists) -/// @param[out] *p2 : second parameter extract (if it exists) -/// @param[out] *p3 : third parameter extract (if it exists) -/// @param[out] *p4 : fourth parameter extract (if it exists) -/// @returns Type of Word : the type of word [0..4] (0 := undetect) -int HmpidDecoder::checkType(uint32_t wp, int* p1, int* p2, int* p3, int* p4) -{ - if ((wp & 0x0000ffff) == 0x000036A8 || (wp & 0x0000ffff) == 0x000032A8 || (wp & 0x0000ffff) == 0x000030A0 || (wp & 0x0800ffff) == 0x080010A0) { - *p2 = (wp & 0x03ff0000) >> 16; // Number of words of row - *p1 = wp & 0x0000ffff; - return (WTYPE_ROW); - } - if ((wp & 0xfff00000) >> 20 == 0xAB0) { - *p2 = (wp & 0x000fff00) >> 8; // Number of words of Segment - *p1 = (wp & 0xfff00000) >> 20; - *p3 = wp & 0x0000000F; - if (*p3 < 4 && *p3 > 0) { - return (WTYPE_EOS); - } - } - // #EX MASK Raul 0x3803FF80 # ex mask 0xF803FF80 - this is EoE marker 0586800B0 - if ((wp & 0x0803FF80) == 0x08000080) { - *p1 = (wp & 0x07c00000) >> 22; - *p2 = (wp & 0x003C0000) >> 18; - *p3 = (wp & 0x0000007F); - if (*p1 < 25 && *p2 < 11) { - return (WTYPE_EOE); - } - } - if ((wp & 0x08000000) == 0) { // # this is a pad - // PAD:0000.0ccc.ccdd.ddnn.nnnn.vvvv.vvvv.vvvv :: c=col,d=dilo,n=chan,v=value - *p1 = (wp & 0x07c00000) >> 22; - *p2 = (wp & 0x003C0000) >> 18; - *p3 = (wp & 0x0003F000) >> 12; - *p4 = (wp & 0x00000FFF); - if (*p1 > 0 && *p1 < 25 && *p2 > 0 && *p2 < 11 && *p3 < 48) { - return (WTYPE_PAD); - } - } else { - return (WTYPE_NONE); - } - return (WTYPE_NONE); -} - -/// Checks if is a Raw Marker and extract the Row Size -/// @param[in] wp : the word to check -/// @param[out] *Err : true if an error is detected -/// @param[out] *rowSize : the number of words of the row -/// @param[out] *mark : the row marker -/// @returns True if Row Marker is detected -bool HmpidDecoder::isRowMarker(uint32_t wp, int* Err, int* rowSize, int* mark) -{ - if ((wp & 0x0000ffff) == 0x36A8 || (wp & 0x0000ffff) == 0x32A8 || (wp & 0x0000ffff) == 0x30A0 || (wp & 0x0800ffff) == 0x080010A0) { - *rowSize = (wp & 0x03ff0000) >> 16; // # Number of words of row - *mark = wp & 0x0000ffff; - *Err = false; - return (true); - } else { - *Err = true; - return (false); - } -} - -/// Checks if is a Segment Marker and extracts the Segment number and the size -/// @param[in] wp : the word to check -/// @param[out] *Err : true if an error is detected -/// @param[out] *segSize : the number of words of the segment -/// @param[out] *Seg : the Segment number [1..3] -/// @param[out] *mark : the Segment Marker -/// @returns True if Segment Marker is detected -bool HmpidDecoder::isSegmentMarker(uint32_t wp, int* Err, int* segSize, int* Seg, int* mark) -{ - *Err = false; - if ((wp & 0xfff00000) >> 20 == 0xAB0) { - *segSize = (wp & 0x000fff00) >> 8; // # Number of words of Segment - *mark = (wp & 0xfff00000) >> 20; - *Seg = wp & 0x0000000F; - if (*Seg > 3 || *Seg < 1) { - LOG(info) << " Wrong segment Marker Word, bad Number of segment" << *Seg << "!"; - *Err = true; - } - return (true); - } else { - return (false); - } -} - -/// Checks if is a PAD Word and extracts all the parameters -/// PAD map : 0000.0ccc.ccdd.ddnn.nnnn.vvvv.vvvv.vvvv :: c=col,d=dilo,n=chan,v=value -/// @param[in] wp : the word to check -/// @param[out] *Err : true if an error is detected -/// @param[out] *Col : the column number [1..24] -/// @param[out] *Dilogic : the dilogic number [1..10] -/// @param[out] *Channel : the channel number [0..47] -/// @param[out] *Charge : the value of Charge [0..4095] -/// @returns True if PAD Word is detected -bool HmpidDecoder::isPadWord(uint32_t wp, int* Err, int* Col, int* Dilogic, int* Channel, int* Charge) -{ - *Err = false; - // if ((wp & 0x08000000) != 0) { - if ((wp & 0x08000000) != 0) { - return (false); - } - *Col = (wp & 0x07c00000) >> 22; - *Dilogic = (wp & 0x003C0000) >> 18; - *Channel = (wp & 0x0003F000) >> 12; - *Charge = (wp & 0x00000FFF); - - if ((wp & 0x0ffff) == 0x036A8 || (wp & 0x0ffff) == 0x032A8 || (wp & 0x0ffff) == 0x030A0 || (wp & 0x0ffff) == 0x010A0) { // # ! this is a pad - if (*Dilogic > 10 || *Channel > 47 || *Dilogic < 1 || *Col > 24 || *Col < 1) { - return (false); - } - } else { - if (*Dilogic > 10 || *Channel > 47 || *Dilogic < 1 || *Col > 24 || *Col < 1) { - // LOG(warning) << " Wrong Pad values Col=" << *Col << " Dilogic=" << *Dilogic << " Channel=" << *Channel << " Charge=" << *Charge << " wp:0x" << std::hex << wp << std::dec; - *Err = true; - return (false); - } - } - return (true); -} - -/// Checks if is a EoE Marker and extracts the Column, Dilogic and the size -/// @param[in] wp : the word to check -/// @param[out] *Err : true if an error is detected -/// @param[out] *Col : the column number [1..24] -/// @param[out] *Dilogic : the dilogic number [1..10] -/// @param[out] *Eoesize : the number of words for dilogic -/// @returns True if EoE marker is detected -bool HmpidDecoder::isEoEmarker(uint32_t wp, int* Err, int* Col, int* Dilogic, int* Eoesize) -{ - *Err = false; - // #EX MASK Raul 0x3803FF80 # ex mask 0xF803FF80 - this is EoE marker 0586800B0 - if ((wp & 0x0803FF80) == 0x08000080) { - *Col = (wp & 0x07c00000) >> 22; - *Dilogic = (wp & 0x003C0000) >> 18; - *Eoesize = (wp & 0x0000007F); - if (*Col > 24 || *Dilogic > 10) { - LOG(info) << " EoE size wrong definition. Col=" << *Col << " Dilogic=" << *Dilogic; - *Err = true; - } - return (true); - } else { - return (false); - } -} - -/// Decode the HMPID error BitMap field (5 bits) and returns true if there are -/// errors and in addition the concat string that contains the error messages -/// ATTENTION : the char * outbuf MUST point to a 250 bytes buffer -/// @param[in] ErrorField : the HMPID Error field -/// @param[out] *outbuf : the output buffer that contains the error description -/// @returns True if EoE marker is detected -bool HmpidDecoder::decodeHmpidError(int ErrorField, char* outbuf) -{ - int res = false; - outbuf[0] = '\0'; - for (int i = 0; i < MAXHMPIDERRORS; i++) { - if ((ErrorField & (0x01 << i)) != 0) { - res = true; - strcat(outbuf, sHmpidErrorDescription[i]); - } - } - return (res); -} - -/// This Decode the Raw Data Header, returns the EquipmentIndex -/// that is obtained with the FLP hardware coords -/// -/// ATTENTION : the 'EquipIndex' parameter and the mEquipment member -/// are different data: the first is the pointer in the Equipments instances -/// array, the second is the FEE_ID number -/// -/// The EVENT_NUMBER : actually is calculated from the ORBIT number -/// -/// @param[in] *streamPtrAdr : the pointer to the Header buffer -/// @param[out] *EquipIndex : the Index to the Equipment Object Array [0..13] -/// @returns True every time -/// @throws TH_WRONGEQUIPINDEX Thrown if the Equipment Index is out of boundary (Equipment not recognized) -int HmpidDecoder::decodeHeader(uint32_t* streamPtrAdr, int* EquipIndex) -{ - uint32_t* buffer = streamPtrAdr; // Sets the pointer to buffer - o2::header::RAWDataHeader* hpt = (o2::header::RAWDataHeader*)buffer; - - /* - mHeFEEID = (buffer[0] & 0x000f0000) >> 16; - mHeSize = (buffer[0] & 0x0000ff00) >> 8; - mHeVer = (buffer[0] & 0x000000ff); - mHePrior = (buffer[1] & 0x000000FF); - mHeDetectorID = (buffer[1] & 0x0000FF00) >> 8; - mHeOffsetNewPack = (buffer[2] & 0x0000FFFF); - mHeMemorySize = (buffer[2] & 0xffff0000) >> 16; - mHeDW = (buffer[3] & 0xF0000000) >> 24; - mHeCruID = (buffer[3] & 0x0FF0000) >> 16; - mHePackNum = (buffer[3] & 0x0000FF00) >> 8; - mHeLinkNum = (buffer[3] & 0x000000FF); - mHeBCDI = (buffer[4] & 0x00000FFF); - mHeORBIT = buffer[5]; - mHeTType = buffer[8]; - mHePageNum = (buffer[9] & 0x0000FFFF); - mHeStop = (buffer[9] & 0x00ff0000) >> 16; - mHeBusy = (buffer[12] & 0xfffffe00) >> 9; - mHeFirmwareVersion = buffer[12] & 0x0000000f; - mHeHmpidError = (buffer[12] & 0x000001F0) >> 4; - mHePAR = buffer[13] & 0x0000FFFF; - */ - mHeFEEID = hpt->feeId; - mHeSize = hpt->headerSize; - mHeVer = hpt->version; - mHePrior = hpt->priority; - mHeDetectorID = hpt->sourceID; - mHeOffsetNewPack = hpt->offsetToNext; - mHeMemorySize = hpt->memorySize; - mHeDW = hpt->endPointID; - mHeCruID = hpt->cruID; - mHePackNum = hpt->packetCounter; - mHeLinkNum = hpt->linkID; - mHeBCDI = hpt->bunchCrossing; - mHeORBIT = hpt->orbit; - mHeTType = hpt->triggerType; - mHePageNum = hpt->pageCnt; - mHeStop = hpt->stop; - mHeBusy = (hpt->detectorField & 0xfffffe00) >> 9; - mHeFirmwareVersion = hpt->detectorField & 0x0000000f; - mHeHmpidError = (hpt->detectorField & 0x000001F0) >> 4; - mHePAR = hpt->detectorPAR; - - *EquipIndex = getEquipmentIndex(mHeCruID, mHeLinkNum); - // mEquipment = (*EquipIndex != -1) ? mTheEquipments[*EquipIndex]->getEquipmentId() : -1; - mEquipment = mHeFEEID & 0x000F; - mNumberWordToRead = ((mHeMemorySize - mHeSize) / sizeof(uint32_t)); - mPayloadTail = ((mHeOffsetNewPack - mHeMemorySize) / sizeof(uint32_t)); - - // ---- Event ID : Actualy based on ORBIT NUMBER and BC - mHeEvent = (mHeORBIT << 12) | mHeBCDI; - - LOG(debug) << "FEE-ID=" << mHeFEEID << " HeSize=" << mHeSize << " HePrior=" << mHePrior << " Det.Id=" << mHeDetectorID << " HeMemorySize=" << mHeMemorySize << " HeOffsetNewPack=" << mHeOffsetNewPack; - LOG(debug) << " Equipment=" << mEquipment << " PakCounter=" << mHePackNum << " Link=" << mHeLinkNum << " CruID=" << mHeCruID << " DW=" << mHeDW << " BC=" << mHeBCDI << " ORBIT=" << mHeORBIT; - LOG(debug) << " TType=" << mHeTType << " HeStop=" << mHeStop << " PagesCounter=" << mHePageNum << " FirmVersion=" << mHeFirmwareVersion << " BusyTime=" << mHeBusy << " Error=" << mHeHmpidError << " PAR=" << mHePAR; - LOG(debug) << " EquIdx = " << *EquipIndex << " Event = " << mHeEvent << " Payload : Words to read=" << mNumberWordToRead << " PailoadTail=" << mPayloadTail; - - if (*EquipIndex == -1) { - LOG(error) << "ERROR ! Bad equipment Number: " << mEquipment; - throw TH_WRONGEQUIPINDEX; - } - // std::cout << "HMPID ! Exit decode header" << std::endl; - return (true); -} - -/// Updates some information related to the Event -/// this function is called at the end of the event -/// @param[in] *eq : the pointer to the Equipment Object -void HmpidDecoder::updateStatistics(HmpidEquipment* eq) -{ - eq->mPadsPerEventAverage = ((eq->mPadsPerEventAverage * (eq->mNumberOfEvents - 1)) + eq->mSampleNumber) / (eq->mNumberOfEvents); - eq->mEventSizeAverage = ((eq->mEventSizeAverage * (eq->mNumberOfEvents - 1)) + eq->mEventSize) / (eq->mNumberOfEvents); - eq->mBusyTimeAverage = ((eq->mBusyTimeAverage * eq->mBusyTimeSamples) + eq->mBusyTimeValue) / (++(eq->mBusyTimeSamples)); - if (eq->mSampleNumber == 0) { - eq->mNumberOfEmptyEvents += 1; - } - if (eq->mErrorsCounter > 0) { - eq->mNumberOfWrongEvents += 1; - } - eq->mTotalPads += eq->mSampleNumber; - eq->mTotalErrors += eq->mErrorsCounter; - - //std::cout << ">>>updateStatistics() >>> "<< eq->getEquipmentId() << "="<< eq->mNumberOfEvents<<" :" << eq->mEventSize <<","<< eq->mTotalPads << ", " << eq->mSampleNumber << std::endl; - - return; -} - -/// Evaluates the content of the header and detect the change of the event -/// with the relevant updates... -/// @param[in] EquipmentIndex : the pointer to the Array of Equipments Array -/// @returns the Pointer to the modified Equipment object -HmpidEquipment* HmpidDecoder::evaluateHeaderContents(int EquipmentIndex) -{ - //std::cout << "Enter evaluateHeaderContents.."; - HmpidEquipment* eq = mTheEquipments[EquipmentIndex]; - if (mHeEvent != eq->mEventNumber) { // Is a new event - if (eq->mEventNumber != OUTRANGEEVENTNUMBER) { // skip the first - updateStatistics(eq); // update previous statistics - } - eq->mNumberOfEvents++; - eq->mEventNumber = mHeEvent; - eq->mBusyTimeValue = mHeBusy * 0.00000005; - eq->mEventSize = 0; // reset the event - eq->mSampleNumber = 0; - eq->mErrorsCounter = 0; - mIntReco = {(uint16_t)mHeBCDI, (uint32_t)mHeORBIT}; - } - eq->mEventSize += mNumberWordToRead * sizeof(uint32_t); // Calculate the size in bytes - if (mHeHmpidError != 0) { - LOG(info) << "HMPID Header reports an error : " << mHeHmpidError; - dumpHmpidError(mHeHmpidError); - eq->setError(ERR_HMPID); - } - // std::cout << ".. end evaluateHeaderContents = " << eq->mEventNumber << std::endl; - return (eq); -} - -/// --------------- Decode One Page from Data Buffer --------------- -/// Read the stream, decode the contents and store resuls. -/// ATTENTION : Assumes that the input stream was set -/// @throws TH_WRONGHEADER Thrown if the Fails to decode the Header -/// @param[in] streamBuf : the pointer to the Pointer of the Stream Buffer -void HmpidDecoder::decodePage(uint32_t** streamBuf) -{ - int equipmentIndex; - try { - getHeaderFromStream(streamBuf); - } catch (int e) { - // The stream end ! - LOG(debug) << "End main decoding loop !"; - throw TH_BUFFEREMPTY; - } - try { - decodeHeader(*streamBuf, &equipmentIndex); - } catch (int e) { - LOG(error) << "Failed to decode the Header !"; - throw TH_WRONGHEADER; - } - - HmpidEquipment* eq = evaluateHeaderContents(equipmentIndex); - - uint32_t wpprev = 0; - uint32_t wp = 0; - int newOne = true; - int p1, p2, p3, p4; - int error; - int type; - bool isIt; - - int payIndex = 0; - while (payIndex < mNumberWordToRead) { //start the payload loop word by word - if (newOne == true) { - wpprev = wp; - if (!getWordFromStream(&wp)) { // end the stream - break; - } - type = checkType(wp, &p1, &p2, &p3, &p4); - if (type == WTYPE_NONE) { - if (eq->mWillBePad == true) { // try to recover the first pad ! - type = checkType((wp & 0xF7FFFFFF), &p1, &p2, &p3, &p4); - if (type == WTYPE_PAD && p3 == 0 && eq->mWordsPerDilogicCounter == 0) { - newOne = false; // # reprocess as pad - continue; - } - } - eq->setError(ERR_NOTKNOWN); - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_NOTKNOWN] << " [" << wp << "]"; - eq->mWordsPerRowCounter++; - eq->mWordsPerSegCounter++; - payIndex++; - continue; - } - } - if (mEquipment == 8) { - LOG(info) << "Event" << eq->mEventNumber << " >" << std::hex << wp << std::dec << "<" << type; - } - if (eq->mWillBeRowMarker == true) { // #shoud be a Row Marker - if (type == WTYPE_ROW) { - eq->mColumnCounter++; - eq->mWordsPerSegCounter++; - eq->mRowSize = p2; - switch (p2) { - case 0: // Empty column - eq->setError(ERR_ROWMARKEMPTY); - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_ROWMARKEMPTY] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; - eq->mWillBeRowMarker = true; - break; - case 0x3FF: // Error in column - eq->setError(ERR_ROWMARKERROR); - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_ROWMARKERROR] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; - eq->mWillBeRowMarker = true; - break; - case 0x3FE: // Masked column - LOG(info) << "Equip=" << mEquipment << "The column=" << (eq->mSegment) * 8 + eq->mColumnCounter << " is Masked !"; - eq->mWillBeRowMarker = true; - break; - default: - eq->mWillBeRowMarker = false; - eq->mWillBePad = true; - break; - } - newOne = true; - } else { - if (wp == wpprev) { - eq->setError(ERR_DUPLICATEPAD); - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_DUPLICATEPAD] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; - newOne = true; - } else if (type == WTYPE_EOE) { // # Could be a EoE - eq->mColumnCounter++; - eq->setError(ERR_ROWMARKWRONG); - eq->mWillBeRowMarker = false; - eq->mWillBePad = true; - newOne = true; - } else if (type == WTYPE_PAD) { //# Could be a PAD - eq->mColumnCounter++; - eq->setError(ERR_ROWMARKLOST); - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_ROWMARKLOST] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; - eq->mWillBeRowMarker = false; - eq->mWillBePad = true; - newOne = true; - } else if (type == WTYPE_EOS) { // # Could be a EoS - eq->mWillBeRowMarker = false; - eq->mWillBeSegmentMarker = true; - newOne = false; - } else { - eq->mColumnCounter++; - eq->setError(ERR_ROWMARKLOST); - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_ROWMARKLOST] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; - eq->mWillBeRowMarker = false; - eq->mWillBePad = true; - newOne = true; - } - } - } else if (eq->mWillBePad == true) { // # We expect a pad - //# PAD:0000.0ccc.ccdd.ddnn.nnnn.vvvv.vvvv.vvvv :: c=col,d=dilo,n=chan,v=value - // c = 1..24 d = 1..10 n = 0..47 - if (type == WTYPE_PAD) { - newOne = true; - if (wp == wpprev) { - eq->setError(ERR_DUPLICATEPAD); - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_DUPLICATEPAD] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; - } else if (p1 != (eq->mSegment * 8 + eq->mColumnCounter)) { // # Manage - // We try to recover the RowMarker misunderstanding - isIt = isRowMarker(wp, &error, &p2, &p1); - if (isIt == true && error == false) { - type = WTYPE_ROW; - newOne = false; - eq->mWillBeEoE = true; - eq->mWillBePad = false; - } else { - LOG(debug) << "Equip=" << mEquipment << " Mismatch in column" - << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; - eq->mColumnCounter = p1 % 8; - } - } else { - setPad(eq, p1 - 1, p2 - 1, p3, p4); - if (mEquipment == 8) { - LOG(info) << "Event" << eq->mEventNumber << " >" << p1 - 1 << "," << p2 - 1 << "," << p3 << "," << p4; - } - eq->mWordsPerDilogicCounter++; - eq->mSampleNumber++; - if (p3 == 47) { - eq->mWillBeEoE = true; - eq->mWillBePad = false; - } - } - eq->mWordsPerRowCounter++; - eq->mWordsPerSegCounter++; - } else if (type == WTYPE_EOE) { //# the pads are end ok - eq->mWillBeEoE = true; - eq->mWillBePad = false; - newOne = false; - } else if (type == WTYPE_ROW) { // # We Lost the EoE ! - // We try to recover the PAD misunderstanding - isIt = isPadWord(wp, &error, &p1, &p2, &p3, &p4); - if (isIt == true && error == false) { - type = WTYPE_PAD; - newOne = false; // # reprocess as pad - } else { - eq->setError(ERR_LOSTEOEMARK); - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_LOSTEOEMARK] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; - eq->mWillBeRowMarker = true; - eq->mWillBePad = false; - newOne = false; - } - } else if (type == WTYPE_EOS) { // # We Lost the EoE ! - eq->setError(ERR_LOSTEOEMARK); - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_LOSTEOEMARK] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; - eq->mWillBeSegmentMarker = true; - eq->mWillBePad = false; - newOne = false; - } - } else if (eq->mWillBeEoE == true) { // # We expect a EoE - if (type == WTYPE_EOE) { - eq->mWordsPerRowCounter++; - eq->mWordsPerSegCounter++; - if (wpprev == wp) { - eq->setError(ERR_DOUBLEEOEMARK); - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_DOUBLEEOEMARK] << " col=" << p1; - } else if (p3 != eq->mWordsPerDilogicCounter) { - eq->setError(ERR_WRONGSIZEINEOE); - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_WRONGSIZEINEOE] << " col=" << p1; - } - eq->mWordsPerDilogicCounter = 0; - if (p2 == 10) { - if (p1 % 8 != 0) { // # we expect the Row Marker - eq->mWillBeRowMarker = true; - } else { - eq->mWillBeSegmentMarker = true; - } - } else { - eq->mWillBePad = true; - } - eq->mWillBeEoE = false; - newOne = true; - } else if (type == WTYPE_EOS) { // We Lost the EoE ! - eq->setError(ERR_LOSTEOEMARK); - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_LOSTEOEMARK] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; - eq->mWillBeSegmentMarker = true; - eq->mWillBeEoE = false; - newOne = false; - } else if (type == WTYPE_ROW) { //# We Lost the EoE ! - eq->setError(ERR_LOSTEOEMARK); - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_LOSTEOEMARK] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; - eq->mWillBeRowMarker = true; - eq->mWillBeEoE = false; - newOne = false; - } else if (type == WTYPE_PAD) { // # We Lost the EoE ! - int typb, p1b, p2b, p3b, p4b; - typb = checkType((wp | 0x08000000), &p1b, &p2b, &p3b, &p4b); - if (typb == WTYPE_EOE && p3b == 48) { - type = typb; - p1 = p1b; - p2 = p2b; - p3 = p3b; - p4 = p4b; - newOne = false; // # reprocess as EoE - } else { - eq->setError(ERR_LOSTEOEMARK); - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_LOSTEOEMARK] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; - eq->mWillBePad = true; - eq->mWillBeEoE = false; - newOne = false; - } - } - } else if (eq->mWillBeSegmentMarker == true) { // # We expect a EoSegment - if (wpprev == wp) { - eq->setError(ERR_DOUBLEMARKWORD); - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_DOUBLEMARKWORD] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; - newOne = true; - } else if (type == 2) { - if (abs(eq->mWordsPerSegCounter - p2) > 5) { - eq->setError(ERR_WRONGSIZESEGMENTMARK); - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_WRONGSIZESEGMENTMARK] << " Seg=" << p2; - } - eq->mWordsPerSegCounter = 0; - eq->mWordsPerRowCounter = 0; - eq->mColumnCounter = 0; - eq->mSegment = p3 % 3; - eq->mWillBeRowMarker = true; - eq->mWillBeSegmentMarker = false; - newOne = true; - } else { - eq->setError(ERR_LOSTEOSMARK); - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_LOSTEOSMARK] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << p1 << "]"; - eq->mWillBeSegmentMarker = false; - eq->mWillBeRowMarker = true; - newOne = false; - } - } - if (newOne) { - payIndex += 1; - } - } - for (int i = 0; i < mPayloadTail; i++) { // move the pointer to skip the Payload Tail - getWordFromStream(&wp); - } -} - -/// --------------- Read Raw Data Buffer --------------- -/// Read the stream, decode the contents and store resuls. -/// ATTENTION : Assumes that the input stream was set -/// @throws TH_WRONGHEADER Thrown if the Fails to decode the Header -bool HmpidDecoder::decodeBuffer() -{ - // ---------resets the PAdMap----------- - for (int i = 0; i < mNumberOfEquipments; i++) { - mTheEquipments[i]->init(); - mTheEquipments[i]->resetPadMap(); - mTheEquipments[i]->resetErrors(); - } - - int type; - int equipmentIndex = -1; - int isIt; - HmpidEquipment* eq; - uint32_t* streamBuf; - LOG(debug) << "Enter decoding !"; - - // Input Stream Main Loop - while (true) { - try { - decodePage(&streamBuf); - } catch (int e) { - LOG(debug) << "End main buffer decoding loop !"; - break; - } - } // this is the end of stream - - // cycle in order to update info for the last event - for (int i = 0; i < mNumberOfEquipments; i++) { - if (mTheEquipments[i]->mNumberOfEvents > 0) { - updateStatistics(mTheEquipments[i]); - } - } - return (true); -} - -/// --------- Decode One Page from Data Buffer with Fast Decoding -------- -/// Read the stream, decode the contents and store resuls. -/// ATTENTION : Assumes that the input stream was set -/// @throws TH_WRONGHEADER Thrown if the Fails to decode the Header -/// @param[in] streamBuf : the pointer to the Pointer of the Stream Buffer -void HmpidDecoder::decodePageFast(uint32_t** streamBuf) -{ - int equipmentIndex; - try { - getHeaderFromStream(streamBuf); - } catch (int e) { - // The stream end ! - LOG(info) << "End Fast Page decoding loop !"; - throw TH_BUFFEREMPTY; - } - try { - decodeHeader(*streamBuf, &equipmentIndex); - } catch (int e) { - LOG(info) << "Failed to decode the Header !"; - throw TH_WRONGHEADER; - } - HmpidEquipment* eq = evaluateHeaderContents(equipmentIndex); - uint32_t wpprev = 0; - uint32_t wp = 0; - int newOne = true; - int Column, Dilogic, Channel, Charge; - int pwer; - int payIndex = 0; - while (payIndex < mNumberWordToRead) { //start the payload loop word by word - wpprev = wp; - if (!getWordFromStream(&wp)) { // end the stream - break; - } - if (wp == wpprev) { - LOG(debug) << "Equip=" << mEquipment << sErrorDescription[ERR_DUPLICATEPAD] << " col=" << (eq->mSegment) * 8 + eq->mColumnCounter << "[" << Column << "]"; - } else { - if (isPadWord(wp, &pwer, &Column, &Dilogic, &Channel, &Charge) == true) { - if (pwer != true) { - setPad(eq, Column - 1, Dilogic - 1, Channel, Charge); - eq->mSampleNumber++; - } - } - } - payIndex += 1; - } - for (int i = 0; i < mPayloadTail; i++) { // move the pointer to skip the Payload Tail - getWordFromStream(&wp); - } - return; -} -/// ---------- Read Raw Data Buffer with Fast Decoding ---------- -/// Read the stream, decode the contents and store resuls. -/// Fast alghoritm : no parsing of control words ! -/// ATTENTION : Assumes that the input stream was set -/// @throws TH_WRONGHEADER Thrown if the Fails to decode the Header -bool HmpidDecoder::decodeBufferFast() -{ - // ---------resets the PAdMap----------- - for (int i = 0; i < mNumberOfEquipments; i++) { - mTheEquipments[i]->init(); - mTheEquipments[i]->resetPadMap(); - } - - uint32_t* streamBuf; - LOG(info) << "Enter FAST decoding !"; - - // Input Stream Main Loop - while (true) { - try { - decodePageFast(&streamBuf); - } catch (int e) { - LOG(info) << " End Buffer Fast Decoding !"; - break; - } - } // this is the end of stream - - // cycle in order to update info for the last event - for (int i = 0; i < mNumberOfEquipments; i++) { - if (mTheEquipments[i]->mNumberOfEvents > 0) { - updateStatistics(mTheEquipments[i]); - } - } - return (true); -} - -// ========================================================= - -/// Getter method to extract Statistic Data in Digit Coords -/// @param[in] Module : the HMPID Module number [0..6] -/// @param[in] Column : the HMPID Module Column number [0..143] -/// @param[in] Row : the HMPID Module Row number [0..159] -/// @returns The Number of entries for specified pad -uint16_t HmpidDecoder::getPadSamples(int Module, int Row, int Column) -{ - int e, c, d, h; - o2::hmpid::Digit::absolute2Equipment(Module, Row, Column, &e, &c, &d, &h); - int EqInd = getEquipmentIndex(e); - if (EqInd < 0) { - return (0); - } - return (mTheEquipments[EqInd]->mPadSamples[c][d][h]); -} - -/// Getter method to extract Statistic Data in Digit Coords -/// @param[in] Module : the HMPID Module number [0..6] -/// @param[in] Column : the HMPID Module Column number [0..143] -/// @param[in] Row : the HMPID Module Row number [0..159] -/// @returns The Sum of Charges for specified pad -double HmpidDecoder::getPadSum(int Module, int Row, int Column) -{ - int e, c, d, h; - o2::hmpid::Digit::absolute2Equipment(Module, Row, Column, &e, &c, &d, &h); - int EqInd = getEquipmentIndex(e); - if (EqInd < 0) { - return (0); - } - return (mTheEquipments[EqInd]->mPadSum[c][d][h]); -} - -/// Getter method to extract Statistic Data in Digit Coords -/// @param[in] Module : the HMPID Module number [0..6] -/// @param[in] Column : the HMPID Module Column number [0..143] -/// @param[in] Row : the HMPID Module Row number [0..159] -/// @returns The Sum of Square Charges for specified pad -double HmpidDecoder::getPadSquares(int Module, int Row, int Column) -{ - int e, c, d, h; - o2::hmpid::Digit::absolute2Equipment(Module, Row, Column, &e, &c, &d, &h); - int EqInd = getEquipmentIndex(e); - if (EqInd < 0) { - return (0); - } - return (mTheEquipments[EqInd]->mPadSquares[c][d][h]); -} - -/// Getter method to extract Statistic Data in Hardware Coords -/// @param[in] EquipmId : the HMPID EquipmentId [0..13] -/// @param[in] Column : the HMPID Module Column number [0..23] -/// @param[in] Dilogic : the HMPID Module Row number [0..9] -/// @param[in] Channel : the HMPID Module Row number [0..47] -/// @returns The Number of Entries for specified pad -uint16_t HmpidDecoder::getChannelSamples(int EquipmId, int Column, int Dilogic, int Channel) -{ - int EqInd = getEquipmentIndex(EquipmId); - if (EqInd < 0) { - return (0); - } - return (mTheEquipments[EqInd]->mPadSamples[Column][Dilogic][Channel]); -} - -/// Getter method to extract Statistic Data in Hardware Coords -/// @param[in] EquipmId : the HMPID EquipmentId [0..13] -/// @param[in] Column : the HMPID Module Column number [0..23] -/// @param[in] Dilogic : the HMPID Module Row number [0..9] -/// @param[in] Channel : the HMPID Module Row number [0..47] -/// @returns The Sum of Charges for specified pad -double HmpidDecoder::getChannelSum(int EquipmId, int Column, int Dilogic, int Channel) -{ - int EqInd = getEquipmentIndex(EquipmId); - if (EqInd < 0) { - return (0); - } - return (mTheEquipments[EqInd]->mPadSum[Column][Dilogic][Channel]); -} - -/// Getter method to extract Statistic Data in Hardware Coords -/// @param[in] EquipmId : the HMPID EquipmentId [0..13] -/// @param[in] Column : the HMPID Module Column number [0..23] -/// @param[in] Dilogic : the HMPID Module Row number [0..9] -/// @param[in] Channel : the HMPID Module Row number [0..47] -/// @returns The Sum of Square Charges for specified pad -double HmpidDecoder::getChannelSquare(int EquipmId, int Column, int Dilogic, int Channel) -{ - int EqInd = getEquipmentIndex(EquipmId); - if (EqInd < 0) { - return (0); - } - return (mTheEquipments[EqInd]->mPadSquares[Column][Dilogic][Channel]); -} - -/// Gets the Average Event Size value -/// @param[in] EquipmId : the HMPID EquipmentId [0..13] -/// @returns The Average Event Size value ( 0 for wrong Equipment Id) -float HmpidDecoder::getAverageEventSize(int EquipmId) -{ - int EqInd = getEquipmentIndex(EquipmId); - if (EqInd < 0) { - return (0.0); - } - return (mTheEquipments[EqInd]->mEventSizeAverage); -} - -/// Gets the Average Busy Time value -/// @param[in] EquipmId : the HMPID EquipmentId [0..13] -/// @returns The Average Busy Time value ( 0 for wrong Equipment Id) -float HmpidDecoder::getAverageBusyTime(int EquipmId) -{ - int EqInd = getEquipmentIndex(EquipmId); - if (EqInd < 0) { - return (0.0); - } - return (mTheEquipments[EqInd]->mBusyTimeAverage); -} - -// =================================================== -// Methods to dump info - -/// Prints on the standard output the table of decoding -/// errors for one equipment -/// @param[in] EquipmId : the HMPID EquipmentId [0..13] -void HmpidDecoder::dumpErrors(int EquipmId) -{ - int EqInd = getEquipmentIndex(EquipmId); - if (EqInd < 0) { - return; - } - std::cout << "Dump Errors for the Equipment = " << EquipmId << std::endl; - for (int i = 0; i < MAXERRORS; i++) { - std::cout << sErrorDescription[i] << " = " << mTheEquipments[EqInd]->mErrors[i] << std::endl; - } - std::cout << " -------- " << std::endl; - return; -} - -/// Prints on the standard output a Table of statistical -/// decoding information for one equipment -/// @param[in] EquipmId : the HMPID EquipmentId [0..13] -/// @type[in] The type of info. 0 = Entries, 1 = Sum, 2 = Sum of squares -void HmpidDecoder::dumpPads(int EquipmId, int type) -{ - int EqInd = getEquipmentIndex(EquipmId); - if (EqInd < 0) { - return; - } - int Module = EquipmId / 2; - int StartRow = (EquipmId % 2 == 1) ? 80 : 0; - int EndRow = (EquipmId % 2 == 1) ? 160 : 80; - std::cout << "Dump Pads for the Equipment = " << EquipmId << std::endl; - for (int c = 0; c < 144; c++) { - for (int r = StartRow; r < EndRow; r++) { - switch (type) { - case 0: - std::cout << getPadSamples(Module, r, c) << ","; - break; - case 1: - std::cout << getPadSum(Module, r, c) << ","; - break; - case 2: - std::cout << getPadSquares(Module, r, c) << ","; - break; - } - } - std::cout << std::endl; - } - std::cout << " -------- " << std::endl; - return; -} - -/// Prints on the standard output the decoded HMPID error field -/// @param[in] ErrorField : the HMPID readout error field -void HmpidDecoder::dumpHmpidError(int ErrorField) -{ - char printbuf[MAXHMPIDERRORS * MAXDESCRIPTIONLENGHT]; - if (decodeHmpidError(ErrorField, printbuf) == true) { - LOG(error) << "HMPID Error field = " << ErrorField << " : " << printbuf; - } - return; -} - -/// Writes in a ASCCI File the complete report of the decoding -/// procedure -/// @param[in] *summaryFileName : the name of the output file -/// @throws TH_CREATEFILE Thrown if was not able to create the file -void HmpidDecoder::writeSummaryFile(char* summaryFileName) -{ - FILE* fs = fopen(summaryFileName, "w"); - if (fs == nullptr) { - printf("Error opening the file %s !\n", summaryFileName); - throw TH_CREATEFILE; - } - - fprintf(fs, "HMPID Readout Raw Data Decoding Summary File\n"); - fprintf(fs, "Equipment Id\t"); - for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { - fprintf(fs, "%d\t", mTheEquipments[i]->getEquipmentId()); - } - fprintf(fs, "\n"); - - fprintf(fs, "Number of events\t"); - for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { - fprintf(fs, "%d\t", mTheEquipments[i]->mNumberOfEvents); - } - fprintf(fs, "\n"); - - fprintf(fs, "Average Event Size\t"); - for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { - fprintf(fs, "%f\t", mTheEquipments[i]->mEventSizeAverage); - } - fprintf(fs, "\n"); - - fprintf(fs, "Total pads\t"); - for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { - fprintf(fs, "%d\t", mTheEquipments[i]->mTotalPads); - } - fprintf(fs, "\n"); - - fprintf(fs, "Average pads per event\t"); - for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { - fprintf(fs, "%f\t", mTheEquipments[i]->mPadsPerEventAverage); - } - fprintf(fs, "\n"); - - fprintf(fs, "Busy Time average\t"); - for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { - fprintf(fs, "%e\t", mTheEquipments[i]->mBusyTimeAverage); - } - fprintf(fs, "\n"); - - fprintf(fs, "Event rate\t"); - for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { - fprintf(fs, "%e\t", 1 / mTheEquipments[i]->mBusyTimeAverage); - } - fprintf(fs, "\n"); - - fprintf(fs, "Number of Empty Events\t"); - for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { - fprintf(fs, "%d\t", mTheEquipments[i]->mNumberOfEmptyEvents); - } - fprintf(fs, "\n"); - - fprintf(fs, "-------------Errors--------------------\n"); - fprintf(fs, "Wrong events\t"); - for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { - fprintf(fs, "%d\t", mTheEquipments[i]->mNumberOfWrongEvents); - } - fprintf(fs, "\n"); - - for (int j = 0; j < MAXERRORS; j++) { - fprintf(fs, "%s\t", sErrorDescription[j]); - for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { - fprintf(fs, "%d\t", mTheEquipments[i]->mErrors[j]); - } - fprintf(fs, "\n"); - } - - fprintf(fs, "Total errors\t"); - for (int i = 0; i < Geo::MAXEQUIPMENTS; i++) { - fprintf(fs, "%d\t", mTheEquipments[i]->mTotalErrors); - } - fprintf(fs, "\n"); - - fclose(fs); - return; -} diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/ClusterizerSpec.h_notused.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/ClusterizerSpec.h_notused.h deleted file mode 100644 index 6102ec481c97c..0000000000000 --- a/Detectors/HMPID/workflow/include/HMPIDWorkflow/ClusterizerSpec.h_notused.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef STEER_DIGITIZERWORKFLOW_HMPIDCLUSTERIZER_H_ -#define STEER_DIGITIZERWORKFLOW_HMPIDCLUSTERIZER_H_ - -#include "Framework/DataProcessorSpec.h" - -namespace o2 -{ -namespace hmpid -{ - -o2::framework::DataProcessorSpec getHMPIDClusterizerSpec(bool useMC); - -} // end namespace hmpid -} // end namespace o2 - -#endif /* STEER_DIGITIZERWORKFLOW_HMPIDCLUSTERIZERSPEC_H_ */ diff --git a/Detectors/HMPID/workflow/include/HMPIDWorkflow/DigitReaderSpec.h_notused.h b/Detectors/HMPID/workflow/include/HMPIDWorkflow/DigitReaderSpec.h_notused.h deleted file mode 100644 index eea9b134bd911..0000000000000 --- a/Detectors/HMPID/workflow/include/HMPIDWorkflow/DigitReaderSpec.h_notused.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file DigitReader.h - -#ifndef O2_HMPID_DIGITREADER -#define O2_HMPID_DIGITREADER - -#include "TFile.h" -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" -#include "DataFormatsHMP/Digit.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" - -namespace o2 -{ -namespace hmpid -{ - -class DigitReader : public o2::framework::Task -{ - public: - DigitReader(bool useMC) : mUseMC(useMC) {} - ~DigitReader() override = default; - void init(o2::framework::InitContext& ic) final; - void run(o2::framework::ProcessingContext& pc) final; - - private: - int mState = 0; - bool mUseMC = true; - std::unique_ptr mFile = nullptr; - - std::vector mDigits, *mPdigits = &mDigits; - - o2::dataformats::MCTruthContainer mLabels, *mPlabels = &mLabels; -}; - -/// read simulated HMPID digits from a root file -framework::DataProcessorSpec getDigitReaderSpec(bool useMC); - -} // namespace hmpid -} // namespace o2 - -#endif /* O2_HMPID_DIGITREADER */ From cb599998aa3f2425b7556f9b97075633065966a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Ku=C4=8Dera?= <26327373+vkucera@users.noreply.github.com> Date: Fri, 20 Feb 2026 13:16:53 +0100 Subject: [PATCH 226/234] FIT: Delete unused files (#15031) --- .../include/FDDReconstruction/ReadRaw.h | 68 -------- .../include/FDDSimulation/Digits2Raw.h | 74 --------- .../include/FDDWorkflow/RawDataProcessSpec.h | 61 ------- .../include/FDDWorkflow/RawDataReaderSpec.h | 84 ---------- .../include/FDDWorkflow/RawWorkflow.h | 28 ---- .../FDD/workflow/src/RawDataProcessSpec.cxx | 52 ------ .../FDD/workflow/src/RawDataReaderSpec.cxx | 24 --- .../FIT/FDD/workflow/src/RawWorkflow.cxx | 42 ----- .../FT0Workflow/FT0DataProcessDPLSpec.h | 61 ------- .../FT0Workflow/FT0DataReaderDPLSpec.h | 110 ------------ .../include/FT0Workflow/FT0Workflow.h | 28 ---- .../include/FT0Workflow/RawReaderFT0.h | 156 ------------------ .../workflow/src/FT0DataProcessDPLSpec.cxx | 52 ------ .../FT0/workflow/src/FT0DataReaderDPLSpec.cxx | 24 --- .../FIT/FT0/workflow/src/FT0Workflow.cxx | 45 ----- .../FIT/FT0/workflow/src/RawReaderFT0.cxx | 13 -- 16 files changed, 922 deletions(-) delete mode 100644 Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/ReadRaw.h delete mode 100644 Detectors/FIT/FDD/simulation/include/FDDSimulation/Digits2Raw.h delete mode 100644 Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataProcessSpec.h delete mode 100644 Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataReaderSpec.h delete mode 100644 Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawWorkflow.h delete mode 100644 Detectors/FIT/FDD/workflow/src/RawDataProcessSpec.cxx delete mode 100644 Detectors/FIT/FDD/workflow/src/RawDataReaderSpec.cxx delete mode 100644 Detectors/FIT/FDD/workflow/src/RawWorkflow.cxx delete mode 100644 Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataProcessDPLSpec.h delete mode 100644 Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataReaderDPLSpec.h delete mode 100644 Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0Workflow.h delete mode 100644 Detectors/FIT/FT0/workflow/include/FT0Workflow/RawReaderFT0.h delete mode 100644 Detectors/FIT/FT0/workflow/src/FT0DataProcessDPLSpec.cxx delete mode 100644 Detectors/FIT/FT0/workflow/src/FT0DataReaderDPLSpec.cxx delete mode 100644 Detectors/FIT/FT0/workflow/src/FT0Workflow.cxx delete mode 100644 Detectors/FIT/FT0/workflow/src/RawReaderFT0.cxx diff --git a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/ReadRaw.h b/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/ReadRaw.h deleted file mode 100644 index 54c8b7b203edb..0000000000000 --- a/Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/ReadRaw.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file ReadRaw.h -/// \brief Reads raw data and converts to digits -/// \author Maciej.Slupecki@cern.ch, arvind.khuntia@cern.ch, based on the FT0 code -// RAW data format description: DataFormat/Detectors/FIT/FDD/RawEventData - -#ifndef ALICEO2_FDD_READRAW_H_ -#define ALICEO2_FDD_READRAW_H_ - -#include -#include -#include -#include -#include -#include -#include -#include "TBranch.h" -#include "TTree.h" -#include "CommonDataFormat/InteractionRecord.h" -#include "DataFormatsFDD/Digit.h" -#include "DataFormatsFDD/ChannelData.h" -#include "DataFormatsFDD/LookUpTable.h" -#include "DataFormatsFDD/RawEventData.h" - -namespace o2 -{ -namespace fdd -{ -class ReadRaw -{ - public: - ReadRaw() = default; - ReadRaw(bool doConversionToDigits, const std::string inputRawFilePath = "fdd.raw", const std::string outputRawFilePath = "fdddigitsFromRaw.root"); - void readRawData(const LookUpTable& lut); - void writeDigits(const std::string& outputDigitsFilePath); - void close(); - - private: - std::ifstream mRawFileIn; - std::map> mDigitAccum; // digit accumulator - - template - TBranch* getOrMakeBranch(TTree& tree, std::string brname, T* ptr) - { - if (auto br = tree.GetBranch(brname.c_str())) { - br->SetAddress(static_cast(ptr)); - return br; - } - // otherwise make it - return tree.Branch(brname.c_str(), ptr); - } - - ClassDefNV(ReadRaw, 1); -}; - -} // namespace fdd -} // namespace o2 -#endif diff --git a/Detectors/FIT/FDD/simulation/include/FDDSimulation/Digits2Raw.h b/Detectors/FIT/FDD/simulation/include/FDDSimulation/Digits2Raw.h deleted file mode 100644 index 4afcf5da37ae8..0000000000000 --- a/Detectors/FIT/FDD/simulation/include/FDDSimulation/Digits2Raw.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file Digits2Raw.h -/// \brief converts digits to raw format -/// \author Maciej.Slupecki@cern.ch -// based on FV0 - -#ifndef ALICEO2_FDD_DIGITS2RAW_H_ -#define ALICEO2_FDD_DIGITS2RAW_H_ - -#include "Headers/RAWDataHeader.h" -#include "CommonDataFormat/InteractionRecord.h" -#include "DataFormatsFDD/RawEventData.h" -#include "DataFormatsFDD/LookUpTable.h" -#include "DataFormatsFDD/ChannelData.h" -#include "DataFormatsFDD/Digit.h" -#include "DetectorsRaw/HBFUtils.h" -#include "DetectorsRaw/RawFileWriter.h" -#include -#include -#include -#include -#include -#include - -namespace o2 -{ -namespace fdd -{ -class Digits2Raw -{ - public: - Digits2Raw() = default; - void readDigits(const std::string& outDir, const std::string& fileDigitsName); - void convertDigits(o2::fdd::Digit bcdigits, - gsl::span pmchannels, - const o2::fdd::LookUpTable& lut); - - o2::raw::RawFileWriter& getWriter() { return mWriter; } - void setFilePerLink(bool v) { mOutputPerLink = v; } - bool getFilePerLink() const { return mOutputPerLink; } - - int carryOverMethod(const header::RDHAny* rdh, const gsl::span data, - const char* ptr, int maxSize, int splitID, - std::vector& trailer, std::vector& header) const; - - private: - static constexpr uint32_t sTcmLink = 2; - static constexpr uint16_t sCruId = 0; - static constexpr uint32_t sEndPointId = sCruId; - - void makeGBTHeader(EventHeader& eventHeader, int link, o2::InteractionRecord const& mIntRecord); - void fillSecondHalfWordAndAddData(int iChannelPerLink, int prevPmLink, const o2::InteractionRecord& ir); - RawEventData mRawEventData; - o2::fdd::Triggers mTriggers; - o2::raw::RawFileWriter mWriter{"FDD"}; - bool mOutputPerLink = false; - ///////////////////////////////////////////////// - - ClassDefNV(Digits2Raw, 1); -}; - -} // namespace fdd -} // namespace o2 -#endif diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataProcessSpec.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataProcessSpec.h deleted file mode 100644 index 6ed465b6181dd..0000000000000 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataProcessSpec.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file RawDataProcessSpec.h - -#ifndef O2_FDD_RAWDATAPROCESSSPEC_H -#define O2_FDD_RAWDATAPROCESSSPEC_H - -#include "Framework/CallbackService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "Framework/Lifetime.h" -#include "Framework/Output.h" -#include "Framework/WorkflowSpec.h" -#include "Framework/SerializationMethods.h" -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" - -#include "FDDRaw/DigitBlockFDD.h" -#include "DataFormatsFDD/Digit.h" -#include "DataFormatsFDD/ChannelData.h" - -#include -#include -#include - -using namespace o2::framework; - -namespace o2 -{ -namespace fdd -{ - -class RawDataProcessSpec : public Task -{ - public: - RawDataProcessSpec(bool dumpEventBlocks) : mDumpEventBlocks(dumpEventBlocks) {} - ~RawDataProcessSpec() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - - private: - bool mDumpEventBlocks; - - o2::header::DataOrigin mOrigin = o2::header::gDataOriginFDD; -}; - -framework::DataProcessorSpec getFDDRawDataProcessSpec(bool dumpProcessor); - -} // namespace fdd -} // namespace o2 - -#endif /* O2_FDDDATAPROCESSDPL_H */ diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataReaderSpec.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataReaderSpec.h deleted file mode 100644 index c3b0349826e98..0000000000000 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataReaderSpec.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file RawDataReaderSpec.h - -#ifndef O2_FDD_RAWDATAREADERSPEC_H -#define O2_FDD_RAWDATAREADERSPEC_H - -#include "DataFormatsFDD/LookUpTable.h" -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" -#include "Framework/CallbackService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "Framework/Lifetime.h" -#include "Framework/Output.h" -#include "Framework/WorkflowSpec.h" -#include "Framework/SerializationMethods.h" -#include "DPLUtils/DPLRawParser.h" -#include "DetectorsRaw/RDHUtils.h" - -#include -#include -#include -using namespace o2::framework; - -namespace o2 -{ -namespace fdd -{ -template -class RawDataReaderSpec : public Task -{ - public: - RawDataReaderSpec(const RawReader& rawReader) : mRawReader(rawReader) {} - RawDataReaderSpec() = default; - ~RawDataReaderSpec() override = default; - void init(InitContext& ic) final { o2::fdd::SingleLUT::Instance().printFullMap(); } - void run(ProcessingContext& pc) final - { - DPLRawParser parser(pc.inputs()); - mRawReader.clear(); - LOG(info) << "FDD RawDataReaderSpec"; - uint64_t count = 0; - for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { - //Proccessing each page - count++; - auto rdhPtr = reinterpret_cast(it.raw()); - gsl::span payload(it.data(), it.size()); - mRawReader.process(payload, o2::raw::RDHUtils::getLinkID(rdhPtr), int(0)); - } - LOG(info) << "Pages: " << count; - mRawReader.accumulateDigits(); - mRawReader.makeSnapshot(pc); - } - RawReader mRawReader; -}; - -template -framework::DataProcessorSpec getFDDRawDataReaderSpec(const RawReader& rawReader) -{ - LOG(info) << "DataProcessorSpec initDataProcSpec() for RawReaderFDD"; - std::vector outputSpec; - RawReader::prepareOutputSpec(outputSpec); - return DataProcessorSpec{ - "fdd-datareader-dpl", - o2::framework::select("TF:FDD/RAWDATA"), - outputSpec, - adaptFromTask>(rawReader), - Options{}}; -} - -} // namespace fdd -} // namespace o2 - -#endif /* O2_FDDDATAREADERDPL_H */ diff --git a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawWorkflow.h b/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawWorkflow.h deleted file mode 100644 index 3bbab66d16497..0000000000000 --- a/Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawWorkflow.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_FDD_RAWWORKFLOW_H -#define O2_FDD_RAWWORKFLOW_H - -/// @file RawWorkflow.h - -#include "Framework/WorkflowSpec.h" - -namespace o2 -{ -namespace fdd -{ -framework::WorkflowSpec getFDDRawWorkflow(bool useProcess, - bool dumpProcessor, bool dumpReader, - bool disableRootOut); -} // namespace fdd -} // namespace o2 -#endif diff --git a/Detectors/FIT/FDD/workflow/src/RawDataProcessSpec.cxx b/Detectors/FIT/FDD/workflow/src/RawDataProcessSpec.cxx deleted file mode 100644 index bf18db67672c2..0000000000000 --- a/Detectors/FIT/FDD/workflow/src/RawDataProcessSpec.cxx +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file RawDataProcessSpec.cxx - -#include "FDDWorkflow/RawDataProcessSpec.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace fdd -{ -using namespace std; -void RawDataProcessSpec::init(InitContext& ic) -{ -} - -void RawDataProcessSpec::run(ProcessingContext& pc) -{ - LOG(info) << "RawDataProcessSpec running..."; - auto vecDigits = pc.inputs().get>("digits"); - auto vecChannelData = pc.inputs().get>("digch"); - if (mDumpEventBlocks) { - DigitBlockFDD::print(vecDigits, vecChannelData); - } -} - -DataProcessorSpec getFDDRawDataProcessSpec(bool dumpProcessor) -{ - std::vector inputSpec; - inputSpec.emplace_back("digits", o2::header::gDataOriginFDD, "DIGITSBC", 0, Lifetime::Timeframe); - inputSpec.emplace_back("digch", o2::header::gDataOriginFDD, "DIGITSCH", 0, Lifetime::Timeframe); - LOG(info) << "DataProcessorSpec getRawDataProcessSpec"; - return DataProcessorSpec{ - "fdd-dataprocess-dpl-flp", - inputSpec, - Outputs{}, - AlgorithmSpec{adaptFromTask(dumpProcessor)}, - Options{}}; -} - -} // namespace fdd -} // namespace o2 diff --git a/Detectors/FIT/FDD/workflow/src/RawDataReaderSpec.cxx b/Detectors/FIT/FDD/workflow/src/RawDataReaderSpec.cxx deleted file mode 100644 index 631655d3038ec..0000000000000 --- a/Detectors/FIT/FDD/workflow/src/RawDataReaderSpec.cxx +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file RawDataReaderSpec.cxx - -#include "FDDWorkflow/RawDataReaderSpec.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace fdd -{ - -} // namespace fdd -} // namespace o2 diff --git a/Detectors/FIT/FDD/workflow/src/RawWorkflow.cxx b/Detectors/FIT/FDD/workflow/src/RawWorkflow.cxx deleted file mode 100644 index c9e5c5be0c81d..0000000000000 --- a/Detectors/FIT/FDD/workflow/src/RawWorkflow.cxx +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file RawWorkflow.cxx - -#include "FDDWorkflow/RawWorkflow.h" -#include "FDDWorkflow/RawDataProcessSpec.h" -#include "FDDWorkflow/RawDataReaderSpec.h" -#include "FDDWorkflow/DigitWriterSpec.h" -#include "FDDWorkflow/RawReaderFDD.h" -namespace o2 -{ -namespace fdd -{ - -framework::WorkflowSpec getFDDRawWorkflow(bool useProcess, - bool dumpProcessor, bool dumpReader, - bool disableRootOut) -{ - LOG(info) << "framework::WorkflowSpec getFDDWorkflow"; - framework::WorkflowSpec specs; - specs.emplace_back(o2::fdd::getFDDRawDataReaderSpec(RawReaderFDD{dumpReader})); - - if (useProcess) { - specs.emplace_back(o2::fdd::getFDDRawDataProcessSpec(dumpProcessor)); - } - if (!disableRootOut) { - specs.emplace_back(o2::fdd::getFDDDigitWriterSpec(false, false)); - } - return specs; -} - -} // namespace fdd -} // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataProcessDPLSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataProcessDPLSpec.h deleted file mode 100644 index 7b7e98d50368e..0000000000000 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataProcessDPLSpec.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file FT0DataProcessDPLSpec.h - -#ifndef O2_FT0DATAPROCESSDPLSPEC_H -#define O2_FT0DATAPROCESSDPLSPEC_H - -#include "Framework/CallbackService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "Framework/Lifetime.h" -#include "Framework/Output.h" -#include "Framework/WorkflowSpec.h" -#include "Framework/SerializationMethods.h" -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" - -#include "FT0Raw/DigitBlockFT0.h" -#include "DataFormatsFT0/Digit.h" -#include "DataFormatsFT0/ChannelData.h" - -#include -#include -#include - -using namespace o2::framework; - -namespace o2 -{ -namespace ft0 -{ - -class FT0DataProcessDPLSpec : public Task -{ - public: - FT0DataProcessDPLSpec(bool dumpEventBlocks) : mDumpEventBlocks(dumpEventBlocks) {} - ~FT0DataProcessDPLSpec() override = default; - void init(InitContext& ic) final; - void run(ProcessingContext& pc) final; - - private: - bool mDumpEventBlocks; - - o2::header::DataOrigin mOrigin = o2::header::gDataOriginFT0; -}; - -framework::DataProcessorSpec getFT0DataProcessDPLSpec(bool dumpProcessor); - -} // namespace ft0 -} // namespace o2 - -#endif /* O2_FT0DATAPROCESSDPL_H */ diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataReaderDPLSpec.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataReaderDPLSpec.h deleted file mode 100644 index 9074f4f7f0f34..0000000000000 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataReaderDPLSpec.h +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file FT0DataReaderDPLSpec.h - -#ifndef O2_FT0DATAREADERDPLSPEC_H -#define O2_FT0DATAREADERDPLSPEC_H -#include "DataFormatsFT0/LookUpTable.h" -#include "Framework/DataProcessorSpec.h" -#include "Framework/Task.h" -#include "Framework/CallbackService.h" -#include "Framework/ConfigParamRegistry.h" -#include "Framework/ControlService.h" -#include "Framework/Lifetime.h" -#include "Framework/Output.h" -#include "Framework/WorkflowSpec.h" -#include "Framework/SerializationMethods.h" -#include "DPLUtils/DPLRawParser.h" -#include "Framework/InputRecordWalker.h" -#include -#include -#include -#include "CommonUtils/VerbosityConfig.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace ft0 -{ -template -class FT0DataReaderDPLSpec : public Task -{ - public: - FT0DataReaderDPLSpec(const RawReader& rawReader) : mRawReader(rawReader) {} - FT0DataReaderDPLSpec() = default; - ~FT0DataReaderDPLSpec() override = default; - typedef RawReader RawReader_t; - void init(InitContext& ic) final { o2::ft0::SingleLUT::Instance().printFullMap(); } - void run(ProcessingContext& pc) final - { - // if we see requested data type input with 0xDEADBEEF subspec and 0 payload this means that the "delayed message" - // mechanism created it in absence of real data from upstream. Processor should send empty output to not block the workflow - { - static size_t contDeadBeef = 0; // number of times 0xDEADBEEF was seen continuously - std::vector dummy{InputSpec{"dummy", ConcreteDataMatcher{o2::header::gDataOriginFT0, o2::header::gDataDescriptionRawData, 0xDEADBEEF}}}; - for (const auto& ref : InputRecordWalker(pc.inputs(), dummy)) { - const auto dh = o2::framework::DataRefUtils::getHeader(ref); - auto payloadSize = DataRefUtils::getPayloadSize(ref); - if (payloadSize == 0) { - auto maxWarn = o2::conf::VerbosityConfig::Instance().maxWarnDeadBeef; - if (++contDeadBeef <= maxWarn) { - LOGP(alarm, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF{}", - dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit, payloadSize, - contDeadBeef == maxWarn ? fmt::format(". {} such inputs in row received, stopping reporting", contDeadBeef) : ""); - } - mRawReader.makeSnapshot(pc); // send empty output - return; - } - } - contDeadBeef = 0; // if good data, reset the counter - } - std::vector filter{InputSpec{"filter", ConcreteDataTypeMatcher{o2::header::gDataOriginFT0, o2::header::gDataDescriptionRawData}, Lifetime::Timeframe}}; - DPLRawParser parser(pc.inputs(), filter); - std::size_t count = 0; - for (auto it = parser.begin(), end = parser.end(); it != end; ++it) { - //Proccessing each page - count++; - auto rdhPtr = reinterpret_cast(it.raw()); - gsl::span payload(it.data(), it.size()); - mRawReader.process(payload, o2::raw::RDHUtils::getLinkID(rdhPtr), o2::raw::RDHUtils::getEndPointID(rdhPtr)); - } - LOG(info) << "Pages: " << count; - mRawReader.accumulateDigits(); - mRawReader.makeSnapshot(pc); - mRawReader.clear(); - } - RawReader_t mRawReader; -}; - -template -framework::DataProcessorSpec getFT0DataReaderDPLSpec(const RawReader& rawReader, bool askSTFDist) -{ - LOG(info) << "DataProcessorSpec initDataProcSpec() for RawReaderFT0"; - std::vector outputSpec; - RawReader::prepareOutputSpec(outputSpec); - std::vector inputSpec{{"STF", ConcreteDataTypeMatcher{o2::header::gDataOriginFT0, "RAWDATA"}, Lifetime::Timeframe}}; - if (askSTFDist) { - inputSpec.emplace_back("STFDist", "FLP", "DISTSUBTIMEFRAME", 0, Lifetime::Timeframe); - } - return DataProcessorSpec{ - "ft0-datareader-dpl", - inputSpec, - outputSpec, - adaptFromTask>(rawReader), - Options{}}; -} - -} // namespace ft0 -} // namespace o2 - -#endif /* O2_FT0DATAREADERDPL_H */ diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0Workflow.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0Workflow.h deleted file mode 100644 index a4988b2c18fc7..0000000000000 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0Workflow.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef O2_FIT_FT0WORKFLOW_H -#define O2_FIT_FT0WORKFLOW_H - -/// @file FT0Workflow.h - -#include "Framework/WorkflowSpec.h" - -namespace o2 -{ -namespace ft0 -{ -framework::WorkflowSpec getFT0Workflow(bool isExtendedMode, bool useProcess, - bool dumpProcessor, bool dumpReader, - bool disableRootOut, bool askSTFDist); -} // namespace ft0 -} // namespace o2 -#endif diff --git a/Detectors/FIT/FT0/workflow/include/FT0Workflow/RawReaderFT0.h b/Detectors/FIT/FT0/workflow/include/FT0Workflow/RawReaderFT0.h deleted file mode 100644 index f7729394db652..0000000000000 --- a/Detectors/FIT/FT0/workflow/include/FT0Workflow/RawReaderFT0.h +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. -// -//file RawReaderFT0.h class for RAW data reading -// -// Artur.Furs -// afurs@cern.ch -// -//Main purpuse is to decode FT0 data blocks and push them to DigitBlockFT0 for proccess -//TODO: prepare wrappers for containers with digits and combine classes below into one template class? -#ifndef ALICEO2_FIT_RAWREADERFT0_H_ -#define ALICEO2_FIT_RAWREADERFT0_H_ -#include -#include -#include -#include "FT0Raw/RawReaderFT0Base.h" - -#include "DataFormatsFT0/Digit.h" -#include "DataFormatsFT0/ChannelData.h" - -#include "Framework/ProcessingContext.h" -#include "Framework/DataAllocator.h" -#include "Framework/OutputSpec.h" -#include - -namespace o2 -{ -namespace ft0 -{ -//Normal TCM mode -template -class RawReaderFT0 : public RawReaderFT0BaseNorm -{ - public: - RawReaderFT0(bool dumpData) : mDumpData(dumpData) {} - RawReaderFT0(const RawReaderFT0&) = default; - - RawReaderFT0() = default; - ~RawReaderFT0() = default; - static constexpr bool sUseTrgInput = useTrgInput; - void clear() - { - mVecDigits.clear(); - if constexpr (sUseTrgInput) { - mVecTriggerInput.clear(); - } - mVecChannelData.clear(); - } - void accumulateDigits() - { - if constexpr (sUseTrgInput) { - getDigits(mVecDigits, mVecChannelData, mVecTriggerInput); - } else { - getDigits(mVecDigits, mVecChannelData); - } - LOG(info) << "Number of Digits: " << mVecDigits.size(); - LOG(info) << "Number of ChannelData: " << mVecChannelData.size(); - if constexpr (sUseTrgInput) { - LOG(info) << "Number of TriggerInput: " << mVecTriggerInput.size(); - } - if (mDumpData) { - DigitBlockFT0::print(mVecDigits, mVecChannelData); - } - } - static void prepareOutputSpec(std::vector& outputSpec) - { - outputSpec.emplace_back(o2::header::gDataOriginFT0, "DIGITSBC", 0, o2::framework::Lifetime::Timeframe); - outputSpec.emplace_back(o2::header::gDataOriginFT0, "DIGITSCH", 0, o2::framework::Lifetime::Timeframe); - if constexpr (sUseTrgInput) { - outputSpec.emplace_back(o2::header::gDataOriginFT0, "TRIGGERINPUT", 0, o2::framework::Lifetime::Timeframe); - } - } - void makeSnapshot(o2::framework::ProcessingContext& pc) - { - pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "DIGITSBC", 0}, mVecDigits); - pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "DIGITSCH", 0}, mVecChannelData); - if constexpr (sUseTrgInput) { - pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "TRIGGERINPUT", 0}, mVecTriggerInput); - } - } - bool mDumpData; - std::vector mVecDigits; - std::vector mVecTriggerInput; - std::vector mVecChannelData; -}; - -//Extended TCM mode (additional raw data struct) -template -class RawReaderFT0ext : public RawReaderFT0BaseExt -{ - public: - RawReaderFT0ext(bool dumpData) : mDumpData(dumpData) {} - RawReaderFT0ext(const RawReaderFT0ext&) = default; - static constexpr bool sUseTrgInput = useTrgInput; - RawReaderFT0ext() = default; - ~RawReaderFT0ext() = default; - void clear() - { - mVecDigits.clear(); - mVecChannelData.clear(); - mVecTrgExt.clear(); - if constexpr (sUseTrgInput) { - mVecTriggerInput.clear(); - } - } - void accumulateDigits() - { - if constexpr (sUseTrgInput) { - getDigits(mVecDigits, mVecChannelData, mVecTrgExt, mVecTriggerInput); - } else { - getDigits(mVecDigits, mVecChannelData, mVecTrgExt); - } - LOG(info) << "Number of Digits: " << mVecDigits.size(); - LOG(info) << "Number of ChannelData: " << mVecChannelData.size(); - LOG(info) << "Number of TriggerExt: " << mVecTrgExt.size(); - if (mDumpData) { - DigitBlockFT0ext::print(mVecDigits, mVecChannelData, mVecTrgExt); - } - } - static void prepareOutputSpec(std::vector& outputSpec) - { - outputSpec.emplace_back(o2::header::gDataOriginFT0, "DIGITSBC", 0, o2::framework::Lifetime::Timeframe); - outputSpec.emplace_back(o2::header::gDataOriginFT0, "DIGITSCH", 0, o2::framework::Lifetime::Timeframe); - outputSpec.emplace_back(o2::header::gDataOriginFT0, "DIGITSTRGEXT", 0, o2::framework::Lifetime::Timeframe); - if constexpr (sUseTrgInput) { - outputSpec.emplace_back(o2::header::gDataOriginFT0, "TRIGGERINPUT", 0, o2::framework::Lifetime::Timeframe); - } - } - void makeSnapshot(o2::framework::ProcessingContext& pc) - { - pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "DIGITSBC", 0}, mVecDigits); - pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "DIGITSCH", 0}, mVecChannelData); - pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "DIGITSTRGEXT", 0}, mVecTrgExt); - if constexpr (sUseTrgInput) { - pc.outputs().snapshot(o2::framework::Output{o2::header::gDataOriginFT0, "TRIGGERINPUT", 0}, mVecTriggerInput); - } - } - bool mDumpData; - std::vector mVecDigits; - std::vector mVecChannelData; - std::vector mVecTrgExt; - std::vector mVecTriggerInput; -}; - -} // namespace ft0 -} // namespace o2 - -#endif diff --git a/Detectors/FIT/FT0/workflow/src/FT0DataProcessDPLSpec.cxx b/Detectors/FIT/FT0/workflow/src/FT0DataProcessDPLSpec.cxx deleted file mode 100644 index d7a7a689d402f..0000000000000 --- a/Detectors/FIT/FT0/workflow/src/FT0DataProcessDPLSpec.cxx +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file FT0DataProcessDPLSpec.cxx - -#include "FT0Workflow/FT0DataProcessDPLSpec.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace ft0 -{ -using namespace std; -void FT0DataProcessDPLSpec::init(InitContext& ic) -{ -} - -void FT0DataProcessDPLSpec::run(ProcessingContext& pc) -{ - LOG(info) << "FT0DataProcessDPLSpec running..."; - auto vecDigits = pc.inputs().get>("digits"); - auto vecChannelData = pc.inputs().get>("digch"); - if (mDumpEventBlocks) { - DigitBlockFT0::print(vecDigits, vecChannelData); - } -} - -DataProcessorSpec getFT0DataProcessDPLSpec(bool dumpProcessor) -{ - std::vector inputSpec; - inputSpec.emplace_back("digits", o2::header::gDataOriginFT0, "DIGITSBC", 0, Lifetime::Timeframe); - inputSpec.emplace_back("digch", o2::header::gDataOriginFT0, "DIGITSCH", 0, Lifetime::Timeframe); - LOG(info) << "DataProcessorSpec getFT0DataProcessDPLSpec"; - return DataProcessorSpec{ - "ft0-dataprocess-dpl-flp", - inputSpec, - Outputs{}, - AlgorithmSpec{adaptFromTask(dumpProcessor)}, - Options{}}; -} - -} // namespace ft0 -} // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/src/FT0DataReaderDPLSpec.cxx b/Detectors/FIT/FT0/workflow/src/FT0DataReaderDPLSpec.cxx deleted file mode 100644 index caa642794b561..0000000000000 --- a/Detectors/FIT/FT0/workflow/src/FT0DataReaderDPLSpec.cxx +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file FT0DataReaderDPLSpec.cxx - -#include "FT0Workflow/FT0DataReaderDPLSpec.h" - -using namespace o2::framework; - -namespace o2 -{ -namespace ft0 -{ - -} // namespace ft0 -} // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/src/FT0Workflow.cxx b/Detectors/FIT/FT0/workflow/src/FT0Workflow.cxx deleted file mode 100644 index 156feb7dd3e2f..0000000000000 --- a/Detectors/FIT/FT0/workflow/src/FT0Workflow.cxx +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// @file FT0Workflow.cxx - -#include "FT0Workflow/FT0Workflow.h" -#include "FT0Workflow/FT0DataProcessDPLSpec.h" -#include "FT0Workflow/FT0DataReaderDPLSpec.h" -#include "FT0Workflow/FT0DigitWriterSpec.h" -#include "FT0Workflow/RawReaderFT0.h" -namespace o2 -{ -namespace ft0 -{ - -framework::WorkflowSpec getFT0Workflow(bool isExtendedMode, bool useProcess, - bool dumpProcessor, bool dumpReader, - bool disableRootOut, bool askSTFDist) -{ - LOG(info) << "framework::WorkflowSpec getFT0Workflow"; - framework::WorkflowSpec specs; - if (isExtendedMode) { - specs.emplace_back(o2::ft0::getFT0DataReaderDPLSpec(RawReaderFT0ext{dumpReader}, askSTFDist)); - } else { - specs.emplace_back(o2::ft0::getFT0DataReaderDPLSpec(RawReaderFT0{dumpReader}, askSTFDist)); - } - if (useProcess) { - specs.emplace_back(o2::ft0::getFT0DataProcessDPLSpec(dumpProcessor)); - } - if (!disableRootOut) { - specs.emplace_back(o2::ft0::getFT0DigitWriterSpec(false, false)); - } - return specs; -} - -} // namespace ft0 -} // namespace o2 diff --git a/Detectors/FIT/FT0/workflow/src/RawReaderFT0.cxx b/Detectors/FIT/FT0/workflow/src/RawReaderFT0.cxx deleted file mode 100644 index b2ef17e540112..0000000000000 --- a/Detectors/FIT/FT0/workflow/src/RawReaderFT0.cxx +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#include "FT0Workflow/RawReaderFT0.h" -using namespace o2::ft0; From ca1c2128b44820ff63518d0d298664c716cd4cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Piero=C5=BCak?= <94726725+wpierozak@users.noreply.github.com> Date: Fri, 20 Feb 2026 17:47:38 +0100 Subject: [PATCH 227/234] FT0: Implemented condition on sum of amplitudes in EventsPerBc calibration (#15084) Co-authored-by: wpierozak --- .../include/FT0Calibration/EventsPerBcCalibrator.h | 6 ++++-- Detectors/FIT/FT0/calibration/src/EventsPerBcCalibrator.cxx | 6 +++--- .../workflow/FT0EventsPerBcProcessor-Workflow.cxx | 3 ++- Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcSpec.h | 6 +++++- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Detectors/FIT/FT0/calibration/include/FT0Calibration/EventsPerBcCalibrator.h b/Detectors/FIT/FT0/calibration/include/FT0Calibration/EventsPerBcCalibrator.h index f44824517f258..d831cc36201ab 100644 --- a/Detectors/FIT/FT0/calibration/include/FT0Calibration/EventsPerBcCalibrator.h +++ b/Detectors/FIT/FT0/calibration/include/FT0Calibration/EventsPerBcCalibrator.h @@ -31,7 +31,7 @@ namespace o2::ft0 { struct EventsPerBcContainer { - EventsPerBcContainer(int32_t minAmplitudeSideA, int32_t minAmplitudeSideC) : mMinAmplitudeSideA(minAmplitudeSideA), mMinAmplitudeSideC(minAmplitudeSideC) {} + EventsPerBcContainer(int32_t minAmplitudeSideA, int32_t minAmplitudeSideC, int32_t minSumOfAmplitude) : mMinAmplitudeSideA(minAmplitudeSideA), mMinAmplitudeSideC(minAmplitudeSideC), mMinSumOfAmplitude(minSumOfAmplitude) {} size_t getEntries() const { return entries; } void print() const; @@ -40,6 +40,7 @@ struct EventsPerBcContainer { const int32_t mMinAmplitudeSideA; const int32_t mMinAmplitudeSideC; + const int32_t mMinSumOfAmplitude; std::array mTvx{0.0}; size_t entries{0}; @@ -56,7 +57,7 @@ class EventsPerBcCalibrator final : public o2::calibration::TimeSlotCalibration< using EventsHistogram = std::array; public: - EventsPerBcCalibrator(uint32_t minNumberOfEntries, int32_t minAmplitudeSideA, int32_t minAmplitudeSideC); + EventsPerBcCalibrator(uint32_t minNumberOfEntries, int32_t minAmplitudeSideA, int32_t minAmplitudeSideC, int32_t minSumOfAmplitude); bool hasEnoughData(const Slot& slot) const override; void initOutput() override; @@ -70,6 +71,7 @@ class EventsPerBcCalibrator final : public o2::calibration::TimeSlotCalibration< const uint32_t mMinNumberOfEntries; const int32_t mMinAmplitudeSideA; const int32_t mMinAmplitudeSideC; + const int32_t mMinSumOfAmplitude; std::vector mTvxPerBcs; std::vector> mTvxPerBcInfos; diff --git a/Detectors/FIT/FT0/calibration/src/EventsPerBcCalibrator.cxx b/Detectors/FIT/FT0/calibration/src/EventsPerBcCalibrator.cxx index a2230f51dc4ea..b17c81213cd08 100644 --- a/Detectors/FIT/FT0/calibration/src/EventsPerBcCalibrator.cxx +++ b/Detectors/FIT/FT0/calibration/src/EventsPerBcCalibrator.cxx @@ -23,7 +23,7 @@ void EventsPerBcContainer::fill(const o2::dataformats::TFIDInfo& ti, const gsl:: { size_t oldEntries = entries; for (const auto& digit : data) { - if (digit.mTriggers.getVertex() && digit.mTriggers.getAmplA() >= mMinAmplitudeSideA && digit.mTriggers.getAmplC() >= mMinAmplitudeSideC) { + if (digit.mTriggers.getVertex() && digit.mTriggers.getAmplA() >= mMinAmplitudeSideA && digit.mTriggers.getAmplC() >= mMinAmplitudeSideC && (digit.mTriggers.getAmplA() + digit.mTriggers.getAmplC()) >= mMinSumOfAmplitude) { mTvx[digit.mIntRecord.bc]++; entries++; } @@ -45,7 +45,7 @@ void EventsPerBcCalibrator::initOutput() mTvxPerBcInfos.clear(); } -EventsPerBcCalibrator::EventsPerBcCalibrator(uint32_t minNumberOfEntries, int32_t minAmplitudeSideA, int32_t minAmplitudeSideC) : mMinNumberOfEntries(minNumberOfEntries), mMinAmplitudeSideA(minAmplitudeSideA), mMinAmplitudeSideC(minAmplitudeSideC) +EventsPerBcCalibrator::EventsPerBcCalibrator(uint32_t minNumberOfEntries, int32_t minAmplitudeSideA, int32_t minAmplitudeSideC, int32_t minSumOfAmplitude) : mMinNumberOfEntries(minNumberOfEntries), mMinAmplitudeSideA(minAmplitudeSideA), mMinAmplitudeSideC(minAmplitudeSideC), mMinSumOfAmplitude(minSumOfAmplitude) { LOG(info) << "Defined threshold for number of entires per slot: " << mMinNumberOfEntries; LOG(info) << "Defined threshold for side A amplitude for event: " << mMinAmplitudeSideA; @@ -75,7 +75,7 @@ EventsPerBcCalibrator::Slot& EventsPerBcCalibrator::emplaceNewSlot(bool front, T { auto& cont = getSlots(); auto& slot = front ? cont.emplace_front(tstart, tend) : cont.emplace_back(tstart, tend); - slot.setContainer(std::make_unique(mMinAmplitudeSideA, mMinAmplitudeSideC)); + slot.setContainer(std::make_unique(mMinAmplitudeSideA, mMinAmplitudeSideC, mMinSumOfAmplitude)); return slot; } } // namespace o2::ft0 \ No newline at end of file diff --git a/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcProcessor-Workflow.cxx b/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcProcessor-Workflow.cxx index ac7a8e52f53b1..5cef707da2cca 100644 --- a/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcProcessor-Workflow.cxx +++ b/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcProcessor-Workflow.cxx @@ -39,7 +39,8 @@ o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext co {"one-object-per-run", VariantType::Bool, false, {"If set, workflow creates only one calibration object per run"}}, {"min-entries-number", VariantType::UInt32, 5000u, {"Minimum number of entries required for a slot to be valid"}}, {"min-ampl-side-a", VariantType::Int, 0, {"Amplitude threshold for Side A events"}}, - {"min-ampl-side-c", VariantType::Int, 0, {"Amplitude threshold for Side C events"}}}}; + {"min-ampl-side-c", VariantType::Int, 0, {"Amplitude threshold for Side C events"}}, + {"min-sum-of-ampl", VariantType::Int, 0, {"Amplitude threshold for sum of A-side and C-side amplitudes"}}}}; WorkflowSpec workflow; workflow.emplace_back(dataProcessorSpec); diff --git a/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcSpec.h b/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcSpec.h index c587ab58fcd90..d493e2a606613 100644 --- a/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcSpec.h +++ b/Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcSpec.h @@ -50,8 +50,11 @@ class FT0EventsPerBcProcessor final : public o2::framework::Task if (ic.options().hasOption("min-ampl-side-c")) { mMinAmplitudeSideC = ic.options().get("min-ampl-side-c"); } + if (ic.options().hasOption("min-sum-of-ampl")) { + mMinSumOfAmplitude = ic.options().get("min-sum-of-ampl"); + } - mCalibrator = std::make_unique(mMinNumberOfEntries, mMinAmplitudeSideA, mMinAmplitudeSideC); + mCalibrator = std::make_unique(mMinNumberOfEntries, mMinAmplitudeSideA, mMinAmplitudeSideC, mMinSumOfAmplitude); if (mOneObjectPerRun) { LOG(info) << "Only one object will be created at the end of run"; @@ -119,6 +122,7 @@ class FT0EventsPerBcProcessor final : public o2::framework::Task uint32_t mMinNumberOfEntries; int32_t mMinAmplitudeSideA; int32_t mMinAmplitudeSideC; + int32_t mMinSumOfAmplitude; }; } // namespace o2::calibration #endif \ No newline at end of file From 4728518ad3cee9c3bb9ab424733e7c79d46fc934 Mon Sep 17 00:00:00 2001 From: Stefano Cannito <143754257+scannito@users.noreply.github.com> Date: Fri, 20 Feb 2026 18:13:21 +0100 Subject: [PATCH 228/234] [ALICE] Fix TRK services crossing (#15085) --- .../Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx index 25c59b3c8fd4a..bd27a5bc30f62 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx @@ -264,8 +264,8 @@ void TRKServices::createMiddleServices(TGeoVolume* motherVolume) // Carbon Fiber Cylinder support for the middle tracker float rMinMiddleCarbonSupport = 34.8f; // Arbitrary value float rMaxMiddleCarbonSupport = 35.f; // 2 mm of carbon fiber - const float zLengthMiddleCarbon = 64.2f; - TGeoTube* middleBarrelCarbonSupport = new TGeoTube("TRK_MID_CARBONSUPPORTsh", rMinMiddleCarbonSupport, rMaxMiddleCarbonSupport, zLengthMiddleCarbon); + const float zLengthMiddleCarbon = 129.f; + TGeoTube* middleBarrelCarbonSupport = new TGeoTube("TRK_MID_CARBONSUPPORTsh", rMinMiddleCarbonSupport, rMaxMiddleCarbonSupport, zLengthMiddleCarbon / 2.); TGeoVolume* middleBarrelCarbonSupportVolume = new TGeoVolume("TRK_MID_CARBONSUPPORT", middleBarrelCarbonSupport, medCFiber); middleBarrelCarbonSupportVolume->SetLineColor(kGray); LOGP(info, "Creating carbon fiber support for Middle Tracker"); @@ -318,7 +318,7 @@ void TRKServices::createMiddleServices(TGeoVolume* motherVolume) // Middle barrel connection disks const float rMinMiddleBarrelDisk = 5.68f; const float rMaxMiddleBarrelDisk = 35.f; - const float zLengthMiddleBarrel = 64.2f; + const float zLengthMiddleBarrel = 64.5f; for (auto& orientation : {Orientation::kASide, Orientation::kCSide}) { TGeoTube* middleBarrelConnDiskSIO2 = new TGeoTube(Form("TRK_MIDBARCONN_DISK_SIO2sh_%s", orientation == Orientation::kASide ? "bwd" : "fwd"), rMinMiddleBarrelDisk, rMaxMiddleBarrelDisk, siO2FiberThick / 2.); TGeoTube* middleBarrelConnDiskPE = new TGeoTube(Form("TRK_MIDBARCONN_DISK_PEsh_%s", orientation == Orientation::kASide ? "bwd" : "fwd"), rMinMiddleBarrelDisk, rMaxMiddleBarrelDisk, peFiberThick / 2.); From 16ee3b839f933da6185705bc9476023d84fc8391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Jacazio?= Date: Fri, 20 Feb 2026 21:00:56 +0100 Subject: [PATCH 229/234] [ALICE3] Add proto segmentation of TF3 (#15081) * Use TF3 CAD specifications --- .../base/include/IOTOFBase/IOTOFBaseParam.h | 2 + .../include/IOTOFSimulation/Detector.h | 2 +- .../include/IOTOFSimulation/Layer.h | 22 +- .../ALICE3/IOTOF/simulation/src/Detector.cxx | 44 ++-- .../ALICE3/IOTOF/simulation/src/Layer.cxx | 237 ++++++++++++++---- .../ALICE3/TRK/base/src/GeometryTGeo.cxx | 1 - 6 files changed, 239 insertions(+), 69 deletions(-) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h index bf605797cbfe5..b74fc6d6869dd 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h @@ -26,6 +26,8 @@ struct IOTOFBaseParam : public o2::conf::ConfigurableParamHelper bool enableForwardTOF = true; bool enableBackwardTOF = true; std::string detectorPattern = ""; + bool segmentedInnerTOF = false; // If the inner TOF layer is segmented + bool segmentedOuterTOF = false; // If the outer TOF layer is segmented O2ParamDef(IOTOFBaseParam, "IOTOFBase"); }; diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Detector.h b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Detector.h index f39a43733ccab..f3c4e3ddd6276 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Detector.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Detector.h @@ -60,7 +60,7 @@ class Detector : public o2::base::DetImpl return nullptr; } - void configLayers(bool itof = true, bool otof = true, bool ftof = true, bool btof = true, std::string pattern = ""); + void configLayers(bool itof = true, bool otof = true, bool ftof = true, bool btof = true, std::string pattern = "", bool itofSegmented = false, bool otofSegmented = false); void configServices(); void createMaterials(); diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Layer.h b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Layer.h index b7cc0a05c1c2e..df3687b2b2ea4 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Layer.h +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Layer.h @@ -14,6 +14,8 @@ #include #include +#include +#include namespace o2 { @@ -23,7 +25,8 @@ class Layer { public: Layer() = default; - Layer(std::string layerName, float rInn, float rOut, float zLength, float zOffset, float layerX2X0, bool isBarrel = true); + Layer(std::string layerName, float rInn, float rOut, float zLength, float zOffset, float layerX2X0, + int layout = kBarrel, int nSegments = 0, float segmentSize = 0.0, int nSensorsPerSegment = 0, double tiltAngle = 0.0); ~Layer() = default; auto getInnerRadius() const { return mInnerRadius; } @@ -33,9 +36,14 @@ class Layer auto getx2X0() const { return mX2X0; } auto getChipThickness() const { return mChipThickness; } auto getName() const { return mLayerName; } - auto getIsBarrel() const { return mIsBarrel; } + auto getLayout() const { return mLayout; } + auto getSegments() const { return mSegments; } + static constexpr int kBarrel = 0; + static constexpr int kDisk = 1; + static constexpr int kBarrelSegmented = 2; + static constexpr int kDiskSegmented = 3; - virtual void createLayer(TGeoVolume* motherVolume){}; + virtual void createLayer(TGeoVolume* motherVolume) {}; protected: std::string mLayerName; @@ -45,7 +53,11 @@ class Layer float mZOffset{0.f}; // Of use when fwd layers float mX2X0; float mChipThickness; - bool mIsBarrel{true}; + int mLayout{kBarrel}; // Identifier of the type of layer layout (barrel, disk, barrel segmented, disk segmented) + // To be used only in case of the segmented layout, to define the number of segments in phi (for barrel) or in r (for disk) + std::pair mSegments{0, 0.0f}; // Number and size of segments in phi (for barrel) or in r (for disk) in case of segmented layout + int mSensorsPerSegment{0}; // Number of sensors along a segment + double mTiltAngle{0.0}; // Tilt angle in degrees to be applied as a rotation around the local center of the segment }; class ITOFLayer : public Layer @@ -53,6 +65,7 @@ class ITOFLayer : public Layer public: using Layer::Layer; virtual void createLayer(TGeoVolume* motherVolume) override; + static std::vector mRegister; }; class OTOFLayer : public Layer @@ -60,6 +73,7 @@ class OTOFLayer : public Layer public: using Layer::Layer; virtual void createLayer(TGeoVolume* motherVolume) override; + static std::vector mRegister; }; class FTOFLayer : public Layer diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx index 3a971e81a610d..0742af3a1340a 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx @@ -40,7 +40,8 @@ Detector::Detector(bool active) auto& iotofPars = IOTOFBaseParam::Instance(); configLayers(iotofPars.enableInnerTOF, iotofPars.enableOuterTOF, iotofPars.enableForwardTOF, iotofPars.enableBackwardTOF, - iotofPars.detectorPattern); + iotofPars.detectorPattern, + iotofPars.segmentedInnerTOF, iotofPars.segmentedOuterTOF); } Detector::~Detector() @@ -56,7 +57,7 @@ void Detector::ConstructGeometry() createGeometry(); } -void Detector::configLayers(bool itof, bool otof, bool ftof, bool btof, std::string pattern) +void Detector::configLayers(bool itof, bool otof, bool ftof, bool btof, std::string pattern, bool itofSegmented, bool otofSegmented) { float radiusInnerTof = 19.f; @@ -65,9 +66,10 @@ void Detector::configLayers(bool itof, bool otof, bool ftof, bool btof, std::str float lengthOuterTof = 680.f; std::pair radiusRangeDiskTof = {15.f, 100.f}; float zForwardTof = 370.f; + LOG(info) << "Configuring IOTOF layers with '" << pattern << "' pattern"; if (pattern == "") { + LOG(info) << "Default pattern"; } else if (pattern == "v3b") { - LOG(info) << "Configuring IOTOF layers with v3b pattern"; ftof = false; btof = false; } else if (pattern == "v3b1a") { @@ -93,17 +95,25 @@ void Detector::configLayers(bool itof, bool otof, bool ftof, bool btof, std::str } else { LOG(fatal) << "IOTOF layer pattern " << pattern << " not recognized, exiting"; } - if (itof) { - mITOFLayer = ITOFLayer(std::string{GeometryTGeo::getITOFLayerPattern()}, radiusInnerTof, 0.f, lengthInnerTof, 0.f, 0.02f, true); // iTOF + if (itof) { // iTOF + mITOFLayer = itofSegmented ? ITOFLayer(std::string{GeometryTGeo::getITOFLayerPattern()}, + radiusInnerTof, 0.f, lengthInnerTof, 0.f, 0.02f, ITOFLayer::kBarrelSegmented, + 24, 5.42, 80, 10) + : ITOFLayer(std::string{GeometryTGeo::getITOFLayerPattern()}, + radiusInnerTof, 0.f, lengthInnerTof, 0.f, 0.02f, ITOFLayer::kBarrel); } - if (otof) { - mOTOFLayer = OTOFLayer(std::string{GeometryTGeo::getOTOFLayerPattern()}, radiusOuterTof, 0.f, lengthOuterTof, 0.f, 0.02f, true); // oTOF + if (otof) { // oTOF + mOTOFLayer = otofSegmented ? OTOFLayer(std::string{GeometryTGeo::getOTOFLayerPattern()}, + radiusOuterTof, 0.f, lengthOuterTof, 0.f, 0.02f, OTOFLayer::kBarrelSegmented, + 62, 9.74, 432, 5) + : OTOFLayer(std::string{GeometryTGeo::getOTOFLayerPattern()}, + radiusOuterTof, 0.f, lengthOuterTof, 0.f, 0.02f, OTOFLayer::kBarrel); } if (ftof) { - mFTOFLayer = FTOFLayer(std::string{GeometryTGeo::getFTOFLayerPattern()}, radiusRangeDiskTof.first, radiusRangeDiskTof.second, 0.f, zForwardTof, 0.02f, false); // fTOF + mFTOFLayer = FTOFLayer(std::string{GeometryTGeo::getFTOFLayerPattern()}, radiusRangeDiskTof.first, radiusRangeDiskTof.second, 0.f, zForwardTof, 0.02f, FTOFLayer::kDisk); // fTOF } if (btof) { - mBTOFLayer = BTOFLayer(std::string{GeometryTGeo::getBTOFLayerPattern()}, radiusRangeDiskTof.first, radiusRangeDiskTof.second, 0.f, -zForwardTof, 0.02f, false); // bTOF + mBTOFLayer = BTOFLayer(std::string{GeometryTGeo::getBTOFLayerPattern()}, radiusRangeDiskTof.first, radiusRangeDiskTof.second, 0.f, -zForwardTof, 0.02f, BTOFLayer::kDisk); // bTOF } } @@ -186,14 +196,18 @@ void Detector::defineSensitiveVolumes() // The names of the IOTOF sensitive volumes have the format: IOTOFLayer(0...mLayers.size()-1) auto& iotofPars = IOTOFBaseParam::Instance(); if (iotofPars.enableInnerTOF) { - v = geoManager->GetVolume(GeometryTGeo::getITOFSensorPattern()); - LOGP(info, "Adding IOTOF Sensitive Volume {}", v->GetName()); - AddSensitiveVolume(v); + for (const std::string& itofSensor : ITOFLayer::mRegister) { + v = geoManager->GetVolume(itofSensor.c_str()); + LOGP(info, "Adding IOTOF Sensitive Volume {}", v->GetName()); + AddSensitiveVolume(v); + } } if (iotofPars.enableOuterTOF) { - v = geoManager->GetVolume(GeometryTGeo::getOTOFSensorPattern()); - LOGP(info, "Adding IOTOF Sensitive Volume {}", v->GetName()); - AddSensitiveVolume(v); + for (const std::string& otofSensor : OTOFLayer::mRegister) { + v = geoManager->GetVolume(otofSensor.c_str()); + LOGP(info, "Adding IOTOF Sensitive Volume {}", v->GetName()); + AddSensitiveVolume(v); + } } if (iotofPars.enableForwardTOF) { v = geoManager->GetVolume(GeometryTGeo::getFTOFSensorPattern()); diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx index 53c07d1fa4978..169a1271da47e 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx @@ -14,84 +14,225 @@ #include "Framework/Logger.h" +#include +#include #include #include +#include + +#include +#include namespace o2 { namespace iotof { -Layer::Layer(std::string layerName, float rInn, float rOut, float zLength, float zOffset, float layerX2X0, bool isBarrel) - : mLayerName(layerName), mInnerRadius(rInn), mOuterRadius(rOut), mZLength(zLength), mZOffset(zOffset), mX2X0(layerX2X0), mIsBarrel(isBarrel) +Layer::Layer(std::string layerName, float rInn, float rOut, float zLength, float zOffset, float layerX2X0, int layout, int nSegments, float segmentSize, int nSensorsPerSegment, double tiltAngle) + : mLayerName(layerName), + mInnerRadius(rInn), + mOuterRadius(rOut), + mZLength(zLength), + mZOffset(zOffset), + mX2X0(layerX2X0), + mLayout(layout), + mSegments(nSegments, segmentSize), + mSensorsPerSegment(nSensorsPerSegment), + mTiltAngle(tiltAngle) { float Si_X0 = 9.5f; mChipThickness = mX2X0 * Si_X0; - if (isBarrel) { - mOuterRadius = mInnerRadius + mChipThickness; - } else { - mZLength = mChipThickness; + std::string name = ""; + switch (layout) { + case kBarrel: + case kBarrelSegmented: + name = "barrel"; + mOuterRadius = mInnerRadius + mChipThickness; + break; + case kDisk: + case kDiskSegmented: + name = "forward"; + mZLength = mChipThickness; + break; + default: + LOG(fatal) << "Invalid layout " << layout; + } + if (1) { // Sanity checks + if (mInnerRadius > mOuterRadius) { + LOG(fatal) << "Invalid layer dimensions: rInner " << mInnerRadius << " cm is larger than rOuter " << mOuterRadius << " cm"; + } + if ((mSegments.first != 0 || mSegments.second != 0.0f) && (layout != kBarrelSegmented && layout != kDiskSegmented)) { + LOG(fatal) << "Invalid configuration: number of segments " << mSegments.first << " is set for non-segmented layout " << layout; + } + if ((mSegments.first <= 1 || mSegments.second <= 0.0f) && (layout == kBarrelSegmented || layout == kDiskSegmented)) { + LOG(fatal) << "Invalid configuration: number of segments " << mSegments.first << " must be positive for segmented layout " << layout; + } + if (mSensorsPerSegment <= 0 && (layout == kBarrelSegmented || layout == kDiskSegmented)) { + LOG(fatal) << "Invalid configuration: number of sensors per segment " << mSensorsPerSegment << " must be positive for segmented layout " << layout; + } + if (std::abs(mTiltAngle) > 0.1 && (layout != kBarrelSegmented && layout != kDiskSegmented)) { + LOG(fatal) << "Invalid configuration: tilt angle " << mTiltAngle << " is set for non-segmented layout " << layout; + } } - LOGP(info, "TOF: Creating {} layer: rInner: {} (cm) rOuter: {} (cm) zLength: {} (cm) zOffset: {} x2X0: {}", isBarrel ? std::string("barrel") : std::string("forward"), mInnerRadius, mOuterRadius, mZLength, mZOffset, mX2X0); + + LOGP(info, "TOF: Creating {} layer: rInner: {} (cm) rOuter: {} (cm) zLength: {} (cm) zOffset: {} x2X0: {}", name.c_str(), mInnerRadius, mOuterRadius, mZLength, mZOffset, mX2X0); } +std::vector ITOFLayer::mRegister; void ITOFLayer::createLayer(TGeoVolume* motherVolume) { - std::string chipName = o2::iotof::GeometryTGeo::getITOFChipPattern(), - sensName = o2::iotof::GeometryTGeo::getITOFSensorPattern(); - - TGeoTube* sensor = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); - TGeoTube* chip = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); - TGeoTube* layer = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); + const std::string chipName = o2::iotof::GeometryTGeo::getITOFChipPattern(); + const std::string sensName = o2::iotof::GeometryTGeo::getITOFSensorPattern(); TGeoMedium* medSi = gGeoManager->GetMedium("TF3_SILICON$"); TGeoMedium* medAir = gGeoManager->GetMedium("TF3_AIR$"); - LOGP(info, "Media: {} {}", (void*)medSi, (void*)medAir); - TGeoVolume* sensVol = new TGeoVolume(sensName.c_str(), sensor, medSi); - TGeoVolume* chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); - TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); - sensVol->SetLineColor(kRed + 3); - chipVol->SetLineColor(kRed + 3); - layerVol->SetLineColor(kRed + 3); - - LOGP(info, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); - chipVol->AddNode(sensVol, 1, nullptr); - - LOGP(info, "Inserting {} in {} ", chipVol->GetName(), layerVol->GetName()); - layerVol->AddNode(chipVol, 1, nullptr); - - LOGP(info, "Inserting {} in {} ", layerVol->GetName(), motherVolume->GetName()); - motherVolume->AddNode(layerVol, 1, nullptr); + switch (mLayout) { + case kBarrel: { + TGeoTube* sensor = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); + TGeoTube* chip = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); + TGeoTube* layer = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); + + TGeoVolume* sensVol = new TGeoVolume(sensName.c_str(), sensor, medSi); + TGeoVolume* chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); + TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); + sensVol->SetLineColor(kRed + 3); + chipVol->SetLineColor(kRed + 3); + layerVol->SetLineColor(kRed + 3); + + LOGP(info, "Inserting Barrel {} in {} ", sensVol->GetName(), chipVol->GetName()); + ITOFLayer::mRegister.push_back(sensVol->GetName()); + chipVol->AddNode(sensVol, 1, nullptr); + + LOGP(info, "Inserting Barrel {} in {} ", chipVol->GetName(), layerVol->GetName()); + layerVol->AddNode(chipVol, 1, nullptr); + + LOGP(info, "Inserting Barrel {} in {} ", layerVol->GetName(), motherVolume->GetName()); + motherVolume->AddNode(layerVol, 1, nullptr); + return; + } + case kBarrelSegmented: { + const double circumference = TMath::TwoPi() * 0.5 * (mInnerRadius + mOuterRadius); + const double segmentSize = mSegments.second; // cm circumference / mSegments; + const double avgRadius = 0.5 * (mInnerRadius + mOuterRadius); + TGeoTube* layer = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); + TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); + layerVol->SetLineColor(kRed + 3); + + for (int i = 0; i < mSegments.first; ++i) { + LOGP(info, "iTOF: Creating segment {}/{} with size {} and thickness {}cm", i + 1, mSegments.first, segmentSize, (mOuterRadius - mInnerRadius)); + const double hx = 0.5 * segmentSize; + const double hy = 0.5 * (mOuterRadius - mInnerRadius); + const double hz = 0.5 * mZLength; + TGeoBBox* sensor = new TGeoBBox(hy, hx, hz); + TGeoBBox* chip = new TGeoBBox(hy, hx, hz); + const std::string segmentTag = Form("segment%d", i + 1); + TGeoVolume* sensVol = new TGeoVolume(Form("%s_%s", sensName.c_str(), segmentTag.c_str()), sensor, medSi); + TGeoVolume* chipVol = new TGeoVolume(Form("%s_%s", chipName.c_str(), segmentTag.c_str()), chip, medSi); + sensVol->SetLineColor(kRed + 3); + chipVol->SetLineColor(kRed + 3); + + LOGP(info, " Inserting Barrel {} in {} ", sensVol->GetName(), chipVol->GetName()); + ITOFLayer::mRegister.push_back(sensVol->GetName()); + chipVol->AddNode(sensVol, 1, nullptr); + + const double phi = TMath::TwoPi() * i / mSegments.first; + + LOG(info) << " Tilting angle for segment " << i + 1 << ": " << phi * TMath::RadToDeg() << " degrees"; + const double x = avgRadius * TMath::Cos(phi); + const double y = avgRadius * TMath::Sin(phi); + auto* rotation = new TGeoRotation(Form("segmentRot%d", i + 1), phi * TMath::RadToDeg() + mTiltAngle, 0, 0); + auto* transformation = new TGeoCombiTrans(x, y, 0, rotation); + + LOGP(info, "Inserting Barrel {} in {} ", chipVol->GetName(), layerVol->GetName()); + layerVol->AddNode(chipVol, 1 + i, transformation); + } + LOGP(info, "Inserting Barrel {} in {} at r={} cm", layerVol->GetName(), motherVolume->GetName(), avgRadius); + motherVolume->AddNode(layerVol, 1, nullptr); + return; + } + default: + LOG(fatal) << "Invalid layout " << mLayout; + } } +std::vector OTOFLayer::mRegister; void OTOFLayer::createLayer(TGeoVolume* motherVolume) { std::string chipName = o2::iotof::GeometryTGeo::getOTOFChipPattern(), sensName = o2::iotof::GeometryTGeo::getOTOFSensorPattern(); - TGeoTube* sensor = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); - TGeoTube* chip = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); - TGeoTube* layer = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); - TGeoMedium* medSi = gGeoManager->GetMedium("TF3_SILICON$"); TGeoMedium* medAir = gGeoManager->GetMedium("TF3_AIR$"); + LOGP(info, "Media: {} {}", (void*)medSi, (void*)medAir); - TGeoVolume* sensVol = new TGeoVolume(sensName.c_str(), sensor, medSi); - TGeoVolume* chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); - TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); - sensVol->SetLineColor(kRed + 3); - chipVol->SetLineColor(kRed + 3); - layerVol->SetLineColor(kRed + 3); - - LOGP(info, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); - chipVol->AddNode(sensVol, 1, nullptr); - - LOGP(info, "Inserting {} in {} ", chipVol->GetName(), layerVol->GetName()); - layerVol->AddNode(chipVol, 1, nullptr); - - LOGP(info, "Inserting {} in {} ", layerVol->GetName(), motherVolume->GetName()); - motherVolume->AddNode(layerVol, 1, nullptr); + switch (mLayout) { + case kBarrel: { + TGeoTube* sensor = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); + TGeoTube* chip = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); + TGeoTube* layer = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); + + TGeoVolume* sensVol = new TGeoVolume(sensName.c_str(), sensor, medSi); + TGeoVolume* chipVol = new TGeoVolume(chipName.c_str(), chip, medSi); + TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); + sensVol->SetLineColor(kRed + 3); + chipVol->SetLineColor(kRed + 3); + layerVol->SetLineColor(kRed + 3); + + LOGP(info, "Inserting {} in {} ", sensVol->GetName(), chipVol->GetName()); + OTOFLayer::mRegister.push_back(sensVol->GetName()); + chipVol->AddNode(sensVol, 1, nullptr); + + LOGP(info, "Inserting {} in {} ", chipVol->GetName(), layerVol->GetName()); + layerVol->AddNode(chipVol, 1, nullptr); + + LOGP(info, "Inserting {} in {} ", layerVol->GetName(), motherVolume->GetName()); + motherVolume->AddNode(layerVol, 1, nullptr); + return; + } + case kBarrelSegmented: { + const double circumference = TMath::TwoPi() * 0.5 * (mInnerRadius + mOuterRadius); + const double segmentSize = mSegments.second; // cm circumference / mSegments; + const double avgRadius = 0.5 * (mInnerRadius + mOuterRadius); + TGeoTube* layer = new TGeoTube(mInnerRadius, mOuterRadius, mZLength / 2); + TGeoVolume* layerVol = new TGeoVolume(mLayerName.c_str(), layer, medAir); + layerVol->SetLineColor(kRed + 3); + + for (int i = 0; i < mSegments.first; ++i) { + LOGP(info, "oTOF: Creating segment {}/{} with size {} and thickness {}cm", i + 1, mSegments.first, segmentSize, (mOuterRadius - mInnerRadius)); + const double hx = 0.5 * segmentSize; + const double hy = 0.5 * (mOuterRadius - mInnerRadius); + const double hz = 0.5 * mZLength; + TGeoBBox* sensor = new TGeoBBox(hy, hx, hz); + TGeoBBox* chip = new TGeoBBox(hy, hx, hz); + const std::string segmentTag = Form("segment%d", i + 1); + TGeoVolume* sensVol = new TGeoVolume(Form("%s_%s", sensName.c_str(), segmentTag.c_str()), sensor, medSi); + TGeoVolume* chipVol = new TGeoVolume(Form("%s_%s", chipName.c_str(), segmentTag.c_str()), chip, medSi); + sensVol->SetLineColor(kRed + 3); + chipVol->SetLineColor(kRed + 3); + + LOGP(info, " Inserting Barrel {} in {} ", sensVol->GetName(), chipVol->GetName()); + OTOFLayer::mRegister.push_back(sensVol->GetName()); + chipVol->AddNode(sensVol, 1, nullptr); + + const double phi = TMath::TwoPi() * i / mSegments.first; + + LOG(info) << " Tilting angle for segment " << i + 1 << ": " << phi * TMath::RadToDeg() << " degrees"; + const double x = avgRadius * TMath::Cos(phi); + const double y = avgRadius * TMath::Sin(phi); + auto* rotation = new TGeoRotation(Form("segmentRot%d", i + 1), phi * TMath::RadToDeg() + mTiltAngle, 0, 0); + auto* transformation = new TGeoCombiTrans(x, y, 0, rotation); + + LOGP(info, "Inserting Barrel {} in {} ", chipVol->GetName(), layerVol->GetName()); + layerVol->AddNode(chipVol, 1 + i, transformation); + } + LOGP(info, "Inserting Barrel {} in {} at r={} cm", layerVol->GetName(), motherVolume->GetName(), avgRadius); + motherVolume->AddNode(layerVol, 1, nullptr); + return; + } + default: + LOG(fatal) << "Invalid layout " << mLayout; + } } void FTOFLayer::createLayer(TGeoVolume* motherVolume) diff --git a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx index 059a35520c1a0..d5d37ec00acef 100644 --- a/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx @@ -102,7 +102,6 @@ void GeometryTGeo::Build(int loadTrans) mLastChipIndexMLOT.resize(mNumberOfLayersMLOT); /// ML and OT are part of TRK as the same detector, without disks for (int i = 0; i < mNumberOfLayersMLOT; i++) { - std::cout << "Layer MLOT: " << i << std::endl; mNumberOfStaves[i] = extractNumberOfStavesMLOT(i); mNumberOfHalfStaves[i] = extractNumberOfHalfStavesMLOT(i); mNumberOfModules[i] = extractNumberOfModulesMLOT(i); From f23aa72dfdb3779502c9510526dab12715756c40 Mon Sep 17 00:00:00 2001 From: shahoian Date: Sat, 21 Feb 2026 16:25:38 +0100 Subject: [PATCH 230/234] Add missing reset for FV0 channels vector at TF start --- Detectors/FIT/FV0/workflow/src/ReconstructionSpec.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/Detectors/FIT/FV0/workflow/src/ReconstructionSpec.cxx b/Detectors/FIT/FV0/workflow/src/ReconstructionSpec.cxx index b97186bbf81a8..cdf297b334588 100644 --- a/Detectors/FIT/FV0/workflow/src/ReconstructionSpec.cxx +++ b/Detectors/FIT/FV0/workflow/src/ReconstructionSpec.cxx @@ -42,6 +42,7 @@ void ReconstructionDPL::run(ProcessingContext& pc) { mTimer.Start(false); mRecPoints.clear(); + mRecChData.clear(); auto digits = pc.inputs().get>("digits"); auto digch = pc.inputs().get>("digch"); // RS: if we need to process MC truth, uncomment lines below From 354b12edc5d97890ef6ae952be530323b7c41075 Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 19 Feb 2026 19:42:12 +0100 Subject: [PATCH 231/234] GPU: Improve some error messages --- GPU/GPUTracking/DataCompression/TPCClusterDecompressor.cxx | 4 ++-- GPU/GPUTracking/Global/GPUChainTrackingCompression.cxx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/GPU/GPUTracking/DataCompression/TPCClusterDecompressor.cxx b/GPU/GPUTracking/DataCompression/TPCClusterDecompressor.cxx index cd1717faf178d..51a896c2baf6a 100644 --- a/GPU/GPUTracking/DataCompression/TPCClusterDecompressor.cxx +++ b/GPU/GPUTracking/DataCompression/TPCClusterDecompressor.cxx @@ -43,10 +43,10 @@ int32_t TPCClusterDecompressor::decompress(const CompressedClustersFlat* cluster int32_t TPCClusterDecompressor::decompress(const CompressedClusters* clustersCompressed, o2::tpc::ClusterNativeAccess& clustersNative, std::function allocator, const GPUParam& param, bool deterministicRec) { if (clustersCompressed->nTracks && clustersCompressed->solenoidBz != -1e6f && clustersCompressed->solenoidBz != param.bzkG) { - throw std::runtime_error("Configured solenoid Bz does not match value used for track model encoding"); + throw std::runtime_error("Configured solenoid Bz " + std::to_string(param.bzkG) + " does not match value used for track model encoding " + std::to_string(clustersCompressed->solenoidBz)); } if (clustersCompressed->nTracks && clustersCompressed->maxTimeBin != -1e6 && clustersCompressed->maxTimeBin != param.continuousMaxTimeBin) { - throw std::runtime_error("Configured max time bin does not match value used for track model encoding"); + throw std::runtime_error("Configured max time bin " + std::to_string(param.continuousMaxTimeBin) + " does not match value used for track model encoding " + std::to_string(clustersCompressed->maxTimeBin)); } std::vector clusters[NSECTORS][GPUCA_ROW_COUNT]; std::atomic_flag locks[NSECTORS][GPUCA_ROW_COUNT]; diff --git a/GPU/GPUTracking/Global/GPUChainTrackingCompression.cxx b/GPU/GPUTracking/Global/GPUChainTrackingCompression.cxx index ca1352b3bda1b..89d47d0e1b86c 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingCompression.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingCompression.cxx @@ -273,10 +273,10 @@ int32_t GPUChainTracking::RunTPCDecompression() CompressedClusters& inputGPUShadow = DecompressorShadow.mInputGPU; if (cmprClsHost.nTracks && cmprClsHost.solenoidBz != -1e6f && cmprClsHost.solenoidBz != param().bzkG) { - throw std::runtime_error("Configured solenoid Bz does not match value used for track model encoding"); + throw std::runtime_error("Configured solenoid Bz " + std::to_string(param().bzkG) + " does not match value used for track model encoding " + std::to_string(cmprClsHost.solenoidBz)); } if (cmprClsHost.nTracks && cmprClsHost.maxTimeBin != -1e6 && cmprClsHost.maxTimeBin != param().continuousMaxTimeBin) { - throw std::runtime_error("Configured max time bin does not match value used for track model encoding"); + throw std::runtime_error("Configured max time bin " + std::to_string(param().continuousMaxTimeBin) + " does not match value used for track model encoding " + std::to_string(cmprClsHost.maxTimeBin)); } int32_t inputStream = 0; From 480167460a22dfe0a23f8c2285901c739f719c6c Mon Sep 17 00:00:00 2001 From: David Rohr Date: Wed, 15 Oct 2025 09:44:10 +0200 Subject: [PATCH 232/234] GPU: Improve existing debug dumps --- GPU/GPUTracking/Merger/GPUTPCGMMerger.h | 2 + GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx | 74 ++++++++++--------- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMerger.h b/GPU/GPUTracking/Merger/GPUTPCGMMerger.h index 14974bdec2303..813e3df29e82e 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMerger.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMMerger.h @@ -199,6 +199,8 @@ class GPUTPCGMMerger : public GPUProcessor void DumpRefit(std::ostream& out) const; void DumpFinal(std::ostream& out) const; void DumpLoopers(std::ostream& out) const; + void DumpTrackParam(std::ostream& out) const; + void DumpTrackClusters(std::ostream& out, bool non0StateOnly = false, bool noNDF0 = false) const; template void MergedTrackStreamerInternal(const GPUTPCGMBorderTrack& b1, const GPUTPCGMBorderTrack& b2, const char* name, int32_t sector1, int32_t sector2, int32_t mergeMode, float weight, float frac) const; diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx b/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx index 0a83bf47f5725..f6afc46609a11 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx @@ -43,10 +43,10 @@ using namespace gputpcgmmergertypes; void GPUTPCGMMerger::DumpSectorTracks(std::ostream& out) const { std::streamsize ss = out.precision(); - out << std::setprecision(2); + out << std::setprecision(10); out << "\nTPC Merger Sector Tracks\n"; for (int32_t iSector = 0; iSector < NSECTORS; iSector++) { - out << "Sector Track Info Index " << (mSectorTrackInfoIndex[iSector + 1] - mSectorTrackInfoIndex[iSector]) << " / " << (mSectorTrackInfoIndex[NSECTORS + iSector + 1] - mSectorTrackInfoIndex[NSECTORS + iSector]) << "\n"; + out << "Sector Track Info Sector " << iSector << " Index " << (mSectorTrackInfoIndex[iSector + 1] - mSectorTrackInfoIndex[iSector]) << " / " << (mSectorTrackInfoIndex[NSECTORS + iSector + 1] - mSectorTrackInfoIndex[NSECTORS + iSector]) << "\n"; for (int32_t iGlobal = 0; iGlobal < 2; iGlobal++) { out << " Track type " << iGlobal << "\n"; for (int32_t j = mSectorTrackInfoIndex[iSector + NSECTORS * iGlobal]; j < mSectorTrackInfoIndex[iSector + NSECTORS * iGlobal + 1]; j++) { @@ -134,9 +134,14 @@ void GPUTPCGMMerger::DumpMergedBetweenSectors(std::ostream& out) const void GPUTPCGMMerger::DumpCollected(std::ostream& out) const { - std::streamsize ss = out.precision(); - out << std::setprecision(6); out << "\nTPC Merger Collected Tracks\n"; + DumpTrackParam(out); +} + +void GPUTPCGMMerger::DumpTrackParam(std::ostream& out) const +{ + std::streamsize ss = out.precision(); + out << std::setprecision(10); for (uint32_t i = 0; i < mMemory->nMergedTracks; i++) { const auto& trk = mMergedTracks[i]; const auto& p = trk.GetParam(); @@ -157,33 +162,42 @@ void GPUTPCGMMerger::DumpMergeCE(std::ostream& out) const } } -void GPUTPCGMMerger::DumpFitPrepare(std::ostream& out) const +void GPUTPCGMMerger::DumpTrackClusters(std::ostream& out, bool non0StateOnly, bool noNDF0) const { - out << "\nTPC Merger Refit Prepare\n"; - out << " Sort\n"; - for (uint32_t i = 0; i < mMemory->nMergedTracks; i++) { - out << " " << i << ": " << mTrackOrderAttach[i] << "\n"; - } - out << " Clusters\n"; for (uint32_t j = 0; j < mMemory->nMergedTracks; j++) { const auto& trk = mMergedTracks[j]; - out << " Track " << j << ": "; + if (trk.NClusters() == 0) { + continue; + } + if (noNDF0 && (!trk.OK() || trk.GetParam().GetNDF() < 0)) { + continue; + } + out << " Track " << j << ": (" << trk.NClusters() << "): "; for (uint32_t i = trk.FirstClusterRef(); i < trk.FirstClusterRef() + trk.NClusters(); i++) { - out << j << "/" << (i - trk.FirstClusterRef()) << ": " << mClusters[i].num << "/" << (int32_t)mClusters[i].state << ", "; + if (!non0StateOnly || mClusters[i].state != 0) { + out << j << "/" << (i - trk.FirstClusterRef()) << ": " << (int32_t)mClusters[i].row << "/" << mClusters[i].num << "/" << (int32_t)mClusters[i].state << ", "; + } } out << "\n"; } - uint32_t maxId = mNMaxClusters; +} + +void GPUTPCGMMerger::DumpFitPrepare(std::ostream& out) const +{ + out << "\nTPC Merger Refit Prepare\n"; + out << " Sort\n"; + for (uint32_t i = 0; i < mMemory->nMergedTracks; i++) { + out << " " << i << ": " << mTrackOrderAttach[i] << "\n"; + } + out << " Track Clusters"; + DumpTrackClusters(out); uint32_t j = 0; - for (uint32_t i = 0; i < maxId; i++) { + for (uint32_t i = 0; i < mNMaxClusters; i++) { if ((mClusterAttachment[i] & attachFlagMask) != 0) { - if (++j % 10 == 0) { - out << " Cluster attachment "; + if (j++ % 10 == 0) { + out << "\n Cluster attachment "; } out << i << ": " << (mClusterAttachment[i] & attachTrackMask) << " / " << (mClusterAttachment[i] & attachFlagMask) << " - "; - if (j % 10 == 0) { - out << "\n"; - } } } out << "\n"; @@ -192,7 +206,7 @@ void GPUTPCGMMerger::DumpFitPrepare(std::ostream& out) const void GPUTPCGMMerger::DumpRefit(std::ostream& out) const { std::streamsize ss = out.precision(); - out << std::setprecision(2); + out << std::setprecision(10); out << "\nTPC Merger Refit\n"; for (uint32_t i = 0; i < mMemory->nMergedTracks; i++) { const auto& trk = mMergedTracks[i]; @@ -224,22 +238,10 @@ void GPUTPCGMMerger::DumpLoopers(std::ostream& out) const void GPUTPCGMMerger::DumpFinal(std::ostream& out) const { out << "\nTPC Merger Finalized\n"; - for (uint32_t j = 0; j < mMemory->nMergedTracks; j++) { - const auto& trk = mMergedTracks[j]; - if (trk.NClusters() == 0) { - continue; - } - out << " Track " << j << ": "; - for (uint32_t i = trk.FirstClusterRef(); i < trk.FirstClusterRef() + trk.NClusters(); i++) { - if (mClusters[i].state != 0) { - out << j << "/" << (i - trk.FirstClusterRef()) << ": " << mClusters[i].num << "/" << (int32_t)mClusters[i].state << ", "; - } - } - out << "\n"; - } - uint32_t maxId = mNMaxClusters; + out << "Track Clusters\n"; + DumpTrackClusters(out, true); uint32_t j = 0; - for (uint32_t i = 0; i < maxId; i++) { + for (uint32_t i = 0; i < mNMaxClusters; i++) { if ((mClusterAttachment[i] & attachFlagMask) != 0) { if (++j % 10 == 0) { out << " Cluster attachment "; From a839182762a089481cece2ef7e58a3c7136ac93d Mon Sep 17 00:00:00 2001 From: David Rohr Date: Thu, 19 Feb 2026 22:27:38 +0100 Subject: [PATCH 233/234] GPU TPC: Fix deterministic mode with new cluster removal protection --- GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx index 260781c17406b..eaf181b741918 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx @@ -1852,7 +1852,7 @@ GPUd() void GPUTPCGMMerger::PrepareForFit1(int32_t nBlocks, int32_t nThreads, in if (CAMath::Abs(trk.GetParam().GetQPt() * Param().qptB5Scaler) <= Param().rec.tpc.rejectQPtB5 && !trk.MergedLooper() && trk.Leg() == 0) { weight |= attachProtect; } - mClusterAttachment[mClusters[trk.FirstClusterRef() + j].num] = weight; + CAMath::AtomicMax(&mClusterAttachment[mClusters[trk.FirstClusterRef() + j].num], weight); CAMath::AtomicAdd(&mSharedCount[mClusters[trk.FirstClusterRef() + j].num], 1u); } if (!trk.CCE() && !trk.MergedLooper()) { From 84a89e877a04d98c1969997a3789449ec26887bb Mon Sep 17 00:00:00 2001 From: David Rohr Date: Fri, 20 Feb 2026 00:03:17 +0100 Subject: [PATCH 234/234] GPU TPC: Do not use fitWithoutProjection for now, sometimes broken --- GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx | 21 +++++++++----------- GPU/GPUTracking/Merger/GPUTPCGMMerger.h | 2 +- GPU/GPUTracking/Merger/GPUTPCGMSectorTrack.h | 3 ++- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx index eaf181b741918..3622e51bd663f 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx @@ -555,7 +555,7 @@ GPUd() int32_t GPUTPCGMMerger::RefitSectorTrack(GPUTPCGMSectorTrack& sectorTrack prop.SetMaterialTPC(); prop.SetMaxSinPhi(GPUCA_MAX_SIN_PHI); prop.SetSeedingErrors(true); // Larger errors for seeds, better since we don't start with good hypothesis - prop.SetFitInProjections(false); + prop.SetFitInProjections(true); // TODO: Was false, consider reenabling after fitInProjection is fixed prop.SetPolynomialField(&Param().polynomialField); GPUTPCGMTrackParam trk; trk.X() = inTrack->Param().GetX(); @@ -718,9 +718,6 @@ GPUd() void GPUTPCGMMerger::MergeSectorsPrepareStep2(int32_t nBlocks, int32_t nT } else if (iBorder == 3) { // transport to the middle of the sector and rotate vertically to the border on the right dAlpha = -dAlpha; x0 = GPUTPCGeometry::Row2X(63); - } else if (iBorder == 4) { // transport to the middle of the sßector, w/o rotation - dAlpha = 0; - x0 = GPUTPCGeometry::Row2X(63); } const float maxSin = CAMath::Sin(60.f / 180.f * CAMath::Pi()); @@ -783,14 +780,14 @@ GPUd() void GPUTPCGMMerger::MergeSectorsPrepareStep2(int32_t nBlocks, int32_t nT } template <> -GPUd() void GPUTPCGMMerger::MergeBorderTracks<0>(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, int32_t iSector1, GPUTPCGMBorderTrack* B1, int32_t N1, int32_t iSector2, GPUTPCGMBorderTrack* B2, int32_t N2, int32_t mergeMode) +GPUd() void GPUTPCGMMerger::MergeBorderTracks<0>(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, int32_t iSector1, const GPUTPCGMBorderTrack* B1, int32_t N1, int32_t iSector2, const GPUTPCGMBorderTrack* B2, int32_t N2, int32_t mergeMode) { CADEBUG(GPUInfo("\nMERGING Sectors %d %d NTracks %d %d CROSS %d", iSector1, iSector2, N1, N2, mergeMode)); GPUTPCGMBorderRange* range1 = mBorderRange[iSector1]; GPUTPCGMBorderRange* range2 = mBorderRange[iSector2] + *GetConstantMem()->tpcTrackers[iSector2].NTracks(); bool sameSector = (iSector1 == iSector2); for (int32_t itr = iBlock * nThreads + iThread; itr < N1; itr += nThreads * nBlocks) { - GPUTPCGMBorderTrack& b = B1[itr]; + const GPUTPCGMBorderTrack& b = B1[itr]; float d = CAMath::Max(0.5f, 3.5f * CAMath::Sqrt(b.Cov()[1])); if (CAMath::Abs(b.Par()[4]) * Param().qptB5Scaler >= 20) { d *= 2; @@ -809,7 +806,7 @@ GPUd() void GPUTPCGMMerger::MergeBorderTracks<0>(int32_t nBlocks, int32_t nThrea } if (!sameSector) { for (int32_t itr = iBlock * nThreads + iThread; itr < N2; itr += nThreads * nBlocks) { - GPUTPCGMBorderTrack& b = B2[itr]; + const GPUTPCGMBorderTrack& b = B2[itr]; float d = CAMath::Max(0.5f, 3.5f * CAMath::Sqrt(b.Cov()[1])); if (CAMath::Abs(b.Par()[4]) * Param().qptB5Scaler >= 20) { d *= 2; @@ -827,7 +824,7 @@ GPUd() void GPUTPCGMMerger::MergeBorderTracks<0>(int32_t nBlocks, int32_t nThrea } template <> -GPUd() void GPUTPCGMMerger::MergeBorderTracks<1>(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, int32_t iSector1, GPUTPCGMBorderTrack* B1, int32_t N1, int32_t iSector2, GPUTPCGMBorderTrack* B2, int32_t N2, int32_t mergeMode) +GPUd() void GPUTPCGMMerger::MergeBorderTracks<1>(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, int32_t iSector1, const GPUTPCGMBorderTrack* B1, int32_t N1, int32_t iSector2, const GPUTPCGMBorderTrack* B2, int32_t N2, int32_t mergeMode) { #if !defined(GPUCA_GPUCODE_COMPILEKERNELS) GPUTPCGMBorderRange* range1 = mBorderRange[iSector1]; @@ -860,7 +857,7 @@ GPUd() void GPUTPCGMMerger::MergeBorderTracks<3>(int32_t nBlocks, int32_t nThrea } template <> -GPUd() void GPUTPCGMMerger::MergeBorderTracks<2>(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, int32_t iSector1, GPUTPCGMBorderTrack* B1, int32_t N1, int32_t iSector2, GPUTPCGMBorderTrack* B2, int32_t N2, int32_t mergeMode) +GPUd() void GPUTPCGMMerger::MergeBorderTracks<2>(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, int32_t iSector1, const GPUTPCGMBorderTrack* B1, int32_t N1, int32_t iSector2, const GPUTPCGMBorderTrack* B2, int32_t N2, int32_t mergeMode) { // int32_t statAll = 0, statMerged = 0; float factor2ys = Param().rec.tpc.trackMergerFactor2YS; @@ -887,7 +884,7 @@ GPUd() void GPUTPCGMMerger::MergeBorderTracks<2>(int32_t nBlocks, int32_t nThrea i2++; } - GPUTPCGMBorderTrack& b1 = B1[r1.fId]; + const GPUTPCGMBorderTrack& b1 = B1[r1.fId]; if (b1.NClusters() < minNPartHits) { continue; } @@ -904,7 +901,7 @@ GPUd() void GPUTPCGMMerger::MergeBorderTracks<2>(int32_t nBlocks, int32_t nThrea } // do check - GPUTPCGMBorderTrack& b2 = B2[r2.fId]; + const GPUTPCGMBorderTrack& b2 = B2[r2.fId]; #if defined(GPUCA_MERGER_BY_MC_LABEL) && !defined(GPUCA_GPUCODE) int64_t label1 = GetTrackLabel(b1); int64_t label2 = GetTrackLabel(b2); @@ -1019,7 +1016,7 @@ GPUd() void GPUTPCGMMerger::MergeWithinSectorsPrepare(int32_t nBlocks, int32_t n const float maxSin = CAMath::Sin(60.f / 180.f * CAMath::Pi()); for (int32_t itr = iBlock * nThreads + iThread; itr < SectorTrackInfoLocalTotal(); itr += nThreads * nBlocks) { - GPUTPCGMSectorTrack& track = mSectorTrackInfos[itr]; + const GPUTPCGMSectorTrack& track = mSectorTrackInfos[itr]; int32_t iSector = track.Sector(); GPUTPCGMBorderTrack b; if (track.TransportToX(this, x0, Param().bzCLight, b, maxSin)) { diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMerger.h b/GPU/GPUTracking/Merger/GPUTPCGMMerger.h index 813e3df29e82e..8f554c24c1d8c 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMerger.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMMerger.h @@ -226,7 +226,7 @@ class GPUTPCGMMerger : public GPUProcessor private: GPUd() void MergeSectorsPrepareStep2(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, int32_t iBorder, GPUTPCGMBorderTrack** B, GPUAtomic(uint32_t) * nB, bool useOrigTrackParam = false); template - GPUd() void MergeBorderTracks(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, int32_t iSector1, GPUTPCGMBorderTrack* B1, int32_t N1, int32_t iSector2, GPUTPCGMBorderTrack* B2, int32_t N2, int32_t mergeMode = 0); + GPUd() void MergeBorderTracks(int32_t nBlocks, int32_t nThreads, int32_t iBlock, int32_t iThread, int32_t iSector1, const GPUTPCGMBorderTrack* B1, int32_t N1, int32_t iSector2, const GPUTPCGMBorderTrack* B2, int32_t N2, int32_t mergeMode = 0); GPUd() void MergeCEFill(const GPUTPCGMSectorTrack* track, const GPUTPCGMMergedTrackHit& cls, int32_t itr); diff --git a/GPU/GPUTracking/Merger/GPUTPCGMSectorTrack.h b/GPU/GPUTracking/Merger/GPUTPCGMSectorTrack.h index 60febbb4428f6..84102cd14ce5c 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMSectorTrack.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMSectorTrack.h @@ -54,6 +54,7 @@ class GPUTPCGMSectorTrack GPUd() float SecPhi() const { return mParam.mSecPhi; } GPUd() float DzDs() const { return mParam.mDzDs; } GPUd() float QPt() const { return mParam.mQPt; } + GPUd() const auto& Param() const { return mParam; } GPUd() float TOffset() const { return mTOffset; } GPUd() int32_t LocalTrackId() const { return mLocalTrackId; } @@ -75,7 +76,7 @@ class GPUTPCGMSectorTrack GPUd() void Set(const GPUTPCGMTrackParam& trk, const GPUTPCTrack* sectorTr, float alpha, int32_t sector); GPUd() void SetParam2(const GPUTPCGMTrackParam& trk); GPUd() void Set(const GPUTPCGMMerger* merger, const GPUTPCTrack* sectorTr, float alpha, int32_t sector); - GPUd() void UseParam2() { mParam = mParam2; } + GPUd() void UseParam2() { mParam = mParam2; } // TODO: Clean this up! GPUd() void SetX2(float v) { mParam2.mX = v; } GPUd() float X2() const { return mParam2.mX; }