Project
Loading...
Searching...
No Matches
WorkflowSession.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12#ifndef ALICEO2_ITSMFT_TRACKING_WORKFLOWSESSION_H_
13#define ALICEO2_ITSMFT_TRACKING_WORKFLOWSESSION_H_
14
15#include <algorithm>
16#include <limits>
17#include <string>
18#include <type_traits>
19#include <utility>
20#include <vector>
21#include <gsl/span>
23#include "Framework/Logger.h"
28
30{
43
44// Validate actual source records against the unsigned BC range used by the
45// legacy timing classes before passing them into the tracking workflow.
47 const o2::its::LayerTiming& timing)
48{
49 for (size_t rof = 0; rof < source.rofs.size(); ++rof) {
50 const int64_t begin = source.rofs[rof].getBCData().differenceInBC(origin) +
51 static_cast<int64_t>(timing.mROFDelay) + timing.mROFBias;
52 const int64_t end = begin + timing.mROFLength;
53 if (timing.mROFLength == 0 || begin < 0 || end > std::numeric_limits<o2::its::TimeStampType>::max()) {
54 throw std::runtime_error(std::format("Invalid ROF timing: source={} rof={}", source.id.value(), rof));
55 }
56 }
57}
58
59// The common columns are copied into framework-owned output storage before the
60// session is reset. Detector-specific columns (MFT seed patterns, MC) stay explicit.
61template <typename Allocator, typename Output, typename Staged>
62void copyTrackingOutputColumns(Allocator& outputs, Output rofs, Output tracks, Output indices, const Staged& staged)
63{
64 outputs.template make<std::decay_t<decltype(staged.trackROFs)>>(rofs, staged.trackROFs.begin(), staged.trackROFs.end());
65 outputs.template make<std::decay_t<decltype(staged.tracks)>>(tracks, staged.tracks.begin(), staged.tracks.end());
66 outputs.template make<std::decay_t<decltype(staged.clusterIndices)>>(indices, staged.clusterIndices.begin(), staged.clusterIndices.end());
67}
68
69// Own every backing store borrowed by a single detector's workflow views.
70// Detector-specific selection, truth vertices and output formats stay in the task.
72{
73 public:
74 WorkflowSession(const char* detectorName, int nLayers)
75 : overlap(nLayers), vertices(nLayers), mask(nLayers), upcMask(nLayers), mDetectorName(detectorName) {}
76
78 std::vector<std::vector<uint32_t>> externalIndices;
79 std::vector<std::vector<uint32_t>> clusterSizes;
84
85 class Cleanup
86 {
87 public:
88 explicit Cleanup(WorkflowSession& session) : mSession(session) {}
89 Cleanup(const Cleanup&) = delete;
90 Cleanup& operator=(const Cleanup&) = delete;
92 {
93 if (mResetFrame) {
94 mSession.reset();
95 }
96 mSession.invalidatePublication();
97 }
98 // Both the loader recovery and Tracker::run have already reset a dropped TF.
99 void frameAlreadyReset() noexcept { mResetFrame = false; }
100
101 private:
102 WorkflowSession& mSession;
103 bool mResetFrame = true;
104 };
105 Cleanup cleanupOnExit() { return Cleanup{*this}; }
106
108 {
109 externalIndices.clear();
110 clusterSizes.clear();
112 }
114 {
115 externalIndices.clear();
116 clusterSizes.clear();
117 frame.setROFViews({});
118 }
119
120 template <typename AlpideParameters>
121 std::vector<o2::its::LayerTiming> layerTimings(const AlpideParameters& alpide, int nOrbits,
122 const std::vector<uint32_t>& addTimeError) const
123 {
124 const int nLayers = overlap.getEntries();
125 if (addTimeError.size() != nLayers) {
126 throw std::runtime_error{std::string(mDetectorName) + " CA timing-error layer count differs from the workflow layout"};
127 }
128 std::vector<o2::its::LayerTiming> timings(nLayers);
129 for (int layer = 0; layer < nLayers; ++layer) {
130 const auto length = alpide.getROFLengthInBC(layer);
131 if (length <= 0) {
132 throw std::runtime_error{std::string(mDetectorName) + " CA per-layer ROF timing has a non-positive ROF length"};
133 }
134 const auto rofsPerOrbit = o2::constants::lhc::LHCMaxBunches / static_cast<unsigned int>(length);
135 timings[layer] = {.mNROFsTF = rofsPerOrbit * static_cast<unsigned int>(nOrbits),
136 .mROFLength = static_cast<uint32_t>(length),
137 .mROFDelay = static_cast<uint32_t>(alpide.getROFDelayInBC(layer)),
138 .mROFBias = static_cast<uint32_t>(alpide.getROFBiasInBC(layer)),
139 .mROFAddTimeErr = addTimeError[layer]};
140 if (timings[layer].mNROFsTF == 0) {
141 throw std::runtime_error{std::string(mDetectorName) + " CA per-layer ROF timing yields zero ROFs per TimeFrame"};
142 }
143 }
144 return timings;
145 }
146
147 template <typename AcceptROF>
148 void configureTiming(gsl::span<const o2::its::LayerTiming> timings, AcceptROF&& accept)
149 {
150 const int nLayers = overlap.getEntries();
151 if (timings.size() != nLayers || timings.empty() ||
152 !std::all_of(timings.begin(), timings.end(), [&](const auto& timing) {
153 const auto& first = timings.front();
154 return timing.mROFLength == first.mROFLength && timing.mROFDelay == first.mROFDelay &&
155 timing.mROFBias == first.mROFBias && timing.mROFAddTimeErr == first.mROFAddTimeErr;
156 })) {
157 throw std::runtime_error{std::string(mDetectorName) + " CA per-layer ROF timing configuration has an unexpected layer count or is not uniform"};
158 }
159 // Only owned timing structure survives between TFs. The key includes every
160 // layer's extent and timing fields, so readout/CCDB changes rebuild it.
161 frame.setROFViews({});
162 if (!matchesTiming(timings)) {
163 ROFOverlapTable nextOverlap{nLayers};
164 ROFVertexLookupTable nextVertices{nLayers};
165 for (int layer = 0; layer < nLayers; ++layer) {
166 nextOverlap.defineLayer(layer, timings[layer]);
167 nextVertices.defineLayer(layer, timings[layer]);
168 }
169 nextOverlap.init();
170 nextVertices.init();
171 ROFMaskTable nextMask{nextOverlap};
172 std::vector<o2::its::LayerTiming> nextTimingKey(timings.begin(), timings.end());
173 overlap = std::move(nextOverlap);
174 vertices = std::move(nextVertices);
175 mask = std::move(nextMask);
176 mTimingKey = std::move(nextTimingKey);
177 }
178 // Vertex contents and selection are event-local even on a cache hit. Views
179 // are rebound only after refresh succeeds; a throwing filter leaves no
180 // partially refreshed event published and the next call can reuse the key.
181 vertices.update(nullptr, 0);
182 mask.resetMask();
183 for (int rof = 0; rof < static_cast<int>(timings[0].mNROFsTF); ++rof) {
184 if (accept(rof)) {
185 for (int layer = 0; layer < nLayers; ++layer) {
186 mask.setROFEnabled(layer, rof, 1);
187 }
188 }
189 }
190 frame.setROFViews({overlap.getView(), vertices.getView(), mask.getView(), upcMask.getView()});
191 }
192
193 template <typename Load>
194 bool loadWithRecovery(bool dropOnFailure, Load&& load)
195 {
196 try {
197 load();
198 return true;
199 } catch (const BoundedMemoryResource::MemoryLimitExceeded& error) {
200 LOGP(error, "{} CA loading exceeded memory limit: {}", mDetectorName, error.what());
201 reset();
202 if (!dropOnFailure) {
203 throw;
204 }
205 } catch (const std::bad_alloc& error) {
206 LOGP(error, "{} CA loading allocation failed: {}", mDetectorName, error.what());
207 reset();
208 if (!dropOnFailure) {
209 throw;
210 }
211 } catch (const std::exception& error) {
212 LOGP(error, "{} CA loading failed: {}", mDetectorName, error.what());
213 reset();
214 throw;
215 }
216 return false;
217 }
218
219 template <typename AfterLoad, typename Complete>
221 AfterLoad&& afterLoad, Complete&& complete)
222 {
223 const auto views = frame.getROFViews();
224 if (views.overlap.mLayerCount > 0 && source.rofs.size() != views.overlap.getLayer(0).mNROFsTF) {
225 LOGP(warn, "{} CA ROF count differs from continuous timing expectation: received {} expected {}",
226 mDetectorName, source.rofs.size(), views.overlap.getLayer(0).mNROFsTF);
227 }
228 const auto origin = source.rofs.empty() ? o2::InteractionRecord{} : source.rofs.front().getBCData();
230 if (!source.dictionary) {
231 throw std::runtime_error{std::string(mDetectorName) + " CA tracker cluster dictionary is not available"};
232 }
233 if (views.overlap.mLayerCount <= 0) {
234 throw std::runtime_error{std::string(mDetectorName) + " CA tracker received no adapter-owned runtime ROF timing view"};
235 }
236 const auto& clock = views.overlap.getLayer(0);
238 loadTimeFrameSources(frame, gsl::span<const ClusterSourceInput>{&source, 1},
240 frame.setROFViews(views);
241 for (uint16_t layer = 0; layer < source.layerToSurface.size(); ++layer) {
242 frame.setROFViews(source.layerToSurface[layer].value(), views, layer);
243 }
244 afterLoad(origin);
245 })) {
246 return false;
247 }
248 if (!tracker.run(frame, traits)) {
249 LOGP(warn, "{} CA tracking failed for this TF", mDetectorName);
250 return false;
251 }
252 const auto& statistics = tracker.getRunStatistics();
253 complete(statistics);
254 LOGP(info, "{} CA tracking produced {} tracks in {:.2f} ms", mDetectorName, frame.getGenericTracks().size(), statistics.elapsedMs);
255 return true;
256 }
257
258 private:
259 bool matchesTiming(gsl::span<const o2::its::LayerTiming> timings) const noexcept
260 {
261 if (mTimingKey.size() != timings.size()) {
262 return false;
263 }
264 for (std::size_t layer = 0; layer < timings.size(); ++layer) {
265 const auto& cached = mTimingKey[layer];
266 const auto& next = timings[layer];
267 if (cached.mNROFsTF != next.mNROFsTF || cached.mROFLength != next.mROFLength ||
268 cached.mROFDelay != next.mROFDelay || cached.mROFBias != next.mROFBias ||
269 cached.mROFAddTimeErr != next.mROFAddTimeErr) {
270 return false;
271 }
272 }
273 return true;
274 }
275
276 const char* mDetectorName;
277 std::vector<o2::its::LayerTiming> mTimingKey;
278};
279} // namespace o2::itsmft::tracking
280#endif
header::DataOrigin origin
Shared cluster I/O utilities for ITS and MFT (based on ITStracking/IOUtils.h)
Tracker orchestrator.
std::vector< o2::its::TrackITS > tracks
Header to collect LHC related constants.
const TrackingExecutionPolicy & getExecutionPolicy() const noexcept
Definition Tracker.h:65
Cleanup & operator=(const Cleanup &)=delete
void configureTiming(gsl::span< const o2::its::LayerTiming > timings, AcceptROF &&accept)
std::vector< std::vector< uint32_t > > clusterSizes
bool process(Tracker &tracker, TrackerTraits &traits, ClusterSourceInput source, AfterLoad &&afterLoad, Complete &&complete)
WorkflowSession(const char *detectorName, int nLayers)
std::vector< o2::its::LayerTiming > layerTimings(const AlpideParameters &alpide, int nOrbits, const std::vector< uint32_t > &addTimeError) const
bool loadWithRecovery(bool dropOnFailure, Load &&load)
std::vector< std::vector< uint32_t > > externalIndices
GLuint GLuint end
Definition glcorearb.h:469
GLsizei GLsizei GLchar * source
Definition glcorearb.h:798
GLuint GLsizei GLsizei * length
Definition glcorearb.h:790
GLsizei GLenum const void * indices
Definition glcorearb.h:400
GLenum GLuint GLint GLint layer
Definition glcorearb.h:1310
GLint GLuint mask
Definition glcorearb.h:291
if(ptInv< o2::track::MinPTInv)
void copyTrackingOutputColumns(Allocator &outputs, Output rofs, Output tracks, Output indices, const Staged &staged)
void validateSourceROFTiming(const ClusterSourceInput &source, const o2::InteractionRecord &origin, const o2::its::LayerTiming &timing)
uint32_t trackClusterIndicesSize noexcept
void loadTimeFrameSources(TimeFrame &, gsl::span< const ClusterSourceInput >, SurfaceCatalogView, std::vector< std::vector< uint32_t > > *externalIndicesBySurface=nullptr, std::vector< std::vector< uint32_t > > *clusterSizesBySurface=nullptr)
Definition IOUtils.cxx:337
CATrackerPublicationAction decideCATrackerPublicationAction(bool active, bool success) noexcept
const DetectorConfiguration & getDetectorConfiguration() const noexcept
Definition TimeFrame.h:157
const RuntimeROFViews & getROFViews() const noexcept
Definition TimeFrame.h:128
void setROFViews(RuntimeROFViews views) noexcept
gSystem Load("libO2DetectorsCommonDataFormats")