Skip to content

Commit 8b036bb

Browse files
committed
Further IOUtils cleanup
1 parent 427b86e commit 8b036bb

11 files changed

Lines changed: 111 additions & 63 deletions

Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/IOUtils.h

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,8 @@
3535
#include "DataFormatsITSMFT/TopologyDictionary.h"
3636
#include "ITSMFTTracking/GlobalMeasurement.h"
3737
#include "ITSMFTTracking/Configuration.h"
38-
#include "ITSMFTTracking/ROFViews.h"
3938
#include "ITSMFTTracking/SurfaceDescriptor.h"
4039
#include "ITSMFTTracking/SurfaceMeasurement.h"
41-
#include "ITSMFTTracking/SurfaceTiming.h"
4240
#include "MathUtils/Cartesian.h"
4341
#include "SimulationDataFormat/MCTruthContainer.h"
4442

@@ -126,26 +124,26 @@ struct ClusterSourceInput {
126124
const o2::itsmft::TopologyDictionary* dictionary{nullptr};
127125
const o2::dataformats::MCTruthContainer<o2::MCCompLabel>* labels{nullptr};
128126
gsl::span<const LayerId> layerToSurface{};
129-
ROFTimingConfig timing{};
130-
RuntimeROFViews rofViews{};
131127
};
132128

133129
/// Reset, decode, and normalize all sources into a configured TimeFrame.
130+
/// ROF records supply cluster ranges only. The workflow binds runtime ROF views
131+
/// after loading and owns timing validation independently.
134132
/// Invalid input throws. On failure, the caller must reset the frame before
135133
/// reuse; partially loaded data must not be published.
136134
void loadTimeFrameSources(TimeFrame&, gsl::span<const ClusterSourceInput>,
137-
SurfaceCatalogView, const o2::InteractionRecord&,
135+
SurfaceCatalogView,
138136
std::vector<std::vector<uint32_t>>* externalIndicesBySurface = nullptr,
139137
std::vector<std::vector<uint32_t>>* clusterSizesBySurface = nullptr);
140138

141139
namespace detail
142140
{
143141
void prepareSources(TimeFrame&, const SurfaceCatalogView&, gsl::span<const ClusterSourceInput>,
144142
std::vector<std::vector<uint32_t>>*, std::vector<std::vector<uint32_t>>*, bool requireCompleteMapping = false);
145-
void validateSource(const ClusterSourceInput&, const o2::InteractionRecord&);
143+
void validateClusterRanges(const ClusterSourceInput&);
146144
void appendCluster(TimeFrame&, const SurfaceCatalogView&, const ClusterSourceInput&, const DecodedCluster&,
147145
uint32_t, uint32_t, std::vector<std::vector<uint32_t>>&, std::vector<std::vector<uint32_t>>&);
148-
void bindSourceROFNavigation(TimeFrame&, const ClusterSourceInput&, const std::vector<std::vector<int>>&);
146+
void storeSourceROFClusters(TimeFrame&, const ClusterSourceInput&, const std::vector<std::vector<int>>&);
149147

150148
// Internal loading loop; geometry decoding and synthetic fixtures share the
151149
// same stream consumption, diagnostics and measurement insertion.
@@ -179,7 +177,7 @@ void loadDecodedSource(TimeFrame& frame, const SurfaceCatalogView& catalog, cons
179177
if (patterns != src.patterns.end()) {
180178
throw std::runtime_error(std::format("Trailing cluster pattern data source={} rof={} clusterIndex={}", src.id.value(), static_cast<uint32_t>(src.rofs.size()), static_cast<uint32_t>(src.clusters.size())));
181179
}
182-
bindSourceROFNavigation(frame, src, boundaries);
180+
storeSourceROFClusters(frame, src, boundaries);
183181
}
184182
} // namespace detail
185183

Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/TimeFrame.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ struct TimeFrame {
123123
const auto& getIndexTableUtils(int layer) const { return mIndexTableUtils[layer]; }
124124

125125
void setROFViews(RuntimeROFViews views) noexcept;
126-
void setROFNavigation(std::size_t position, gsl::span<const int> boundaries,
127-
RuntimeROFViews views, uint16_t localLayer);
126+
void setROFViews(std::size_t position, RuntimeROFViews views, uint16_t localLayer);
127+
void setROFClusters(std::size_t position, gsl::span<const int> boundaries);
128128
const RuntimeROFViews& getROFViews() const noexcept { return mROFViews; }
129129
const RuntimeROFViews& getROFViews(int layer) const noexcept { return mROFViewsBySurface.empty() ? mROFViews : mROFViewsBySurface[layer]; }
130130
int getROFLocalLayer(int layer) const noexcept { return mROFLocalLayerBySurface.empty() ? layer : mROFLocalLayerBySurface[layer]; }

Detectors/ITSMFT/common/tracking/include/ITSMFTTracking/WorkflowSession.h

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "ITSMFTTracking/TrackPublicationHelpers.h"
2424
#include "ITSMFTTracking/IOUtils.h"
2525
#include "ITSMFTTracking/ROFLookupTables.h"
26+
#include "ITSMFTTracking/SurfaceTiming.h"
2627
#include "ITSMFTTracking/Tracker.h"
2728

2829
namespace o2::itsmft::tracking
@@ -40,6 +41,19 @@ inline CATrackerPublicationAction decideCATrackerPublicationAction(bool active,
4041
return success ? CATrackerPublicationAction::PublishActiveResult : CATrackerPublicationAction::SkipDroppedTimeFrame;
4142
}
4243

44+
// Timing belongs to the workflow; cluster loading only consumes ROF ranges.
45+
inline void validateSourceROFTiming(const ClusterSourceInput& source, const o2::InteractionRecord& origin,
46+
const ROFTimingConfig& timing)
47+
{
48+
for (uint32_t rof = 0; rof < source.rofs.size(); ++rof) {
49+
const auto built = computeROFIntervalBC(source.rofs[rof].getBCData(), origin, timing, rof);
50+
if (!built.ok()) {
51+
throw std::runtime_error(std::format("Invalid ROF timing: source={} rof={} timingError={}",
52+
source.id.value(), rof, static_cast<int>(built.error)));
53+
}
54+
}
55+
}
56+
4357
// The common columns are copied into framework-owned output storage before the
4458
// session is reset. Detector-specific columns (MFT seed patterns, MC) stay explicit.
4559
template <typename Allocator, typename Output, typename Staged>
@@ -216,10 +230,13 @@ class WorkflowSession
216230
throw std::runtime_error{std::string(mDetectorName) + " CA tracker received no adapter-owned runtime ROF timing view"};
217231
}
218232
const auto& clock = views.overlap.getLayer(0);
219-
source.timing = {clock.mROFLength, clock.mROFDelay, clock.mROFBias, clock.mROFAddTimeErr};
220-
source.rofViews = views;
233+
validateSourceROFTiming(source, origin, {clock.mROFLength, clock.mROFDelay, clock.mROFBias, clock.mROFAddTimeErr});
221234
loadTimeFrameSources(frame, gsl::span<const ClusterSourceInput>{&source, 1},
222-
frame.getDetectorConfiguration().getSurfaceCatalog(), origin, &externalIndices, &clusterSizes);
235+
frame.getDetectorConfiguration().getSurfaceCatalog(), &externalIndices, &clusterSizes);
236+
frame.setROFViews(views);
237+
for (uint16_t layer = 0; layer < source.layerToSurface.size(); ++layer) {
238+
frame.setROFViews(source.layerToSurface[layer].value(), views, layer);
239+
}
223240
afterLoad(origin);
224241
})) {
225242
return false;

Detectors/ITSMFT/common/tracking/src/IOUtils.cxx

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ o2::itsmft::tracking::DecodedCluster decodeCluster(
3232
gsl::span<const unsigned char>::iterator& patterns,
3333
const o2::itsmft::TopologyDictionary* dict)
3434
{
35-
o2::itsmft::tracking::DecodedCluster result;
3635
if (dict == nullptr) {
3736
throw std::runtime_error("Cluster dictionary is not available");
3837
}
@@ -57,19 +56,18 @@ o2::itsmft::tracking::DecodedCluster decodeCluster(
5756
if constexpr (DetId == o2::detectors::DetID::ITS) {
5857
const auto trkXYZ = geom->getMatrixT2L(sensorID) ^ clusterData.coordinates;
5958
const auto gloXYZ = geom->getMatrixL2G(sensorID) * clusterData.coordinates;
60-
result = {{gloXYZ.x(), gloXYZ.y(), gloXYZ.z()},
61-
{trkXYZ.x(), trkXYZ.y(), trkXYZ.z(), geom->getSensorRefAlpha(sensorID)},
62-
{sigma2Row, 0.f, sigma2Col},
63-
clusterData.nPixels,
64-
layer};
59+
return {{gloXYZ.x(), gloXYZ.y(), gloXYZ.z()},
60+
{trkXYZ.x(), trkXYZ.y(), trkXYZ.z(), geom->getSensorRefAlpha(sensorID)},
61+
{sigma2Row, 0.f, sigma2Col},
62+
clusterData.nPixels,
63+
layer};
6564
} else {
6665
if (!geom->getCacheL2G().isFilled() || geom->getCacheL2G().getSize() <= sensorID) {
6766
throw std::runtime_error("Cluster geometry is not available");
6867
}
6968
const auto gloXYZ = geom->getMatrixL2G(sensorID) * clusterData.coordinates;
70-
result = {{gloXYZ.x(), gloXYZ.y(), gloXYZ.z()}, {}, {sigma2Row, 0.f, sigma2Col}, clusterData.nPixels, layer};
69+
return {{gloXYZ.x(), gloXYZ.y(), gloXYZ.z()}, {}, {sigma2Row, 0.f, sigma2Col}, clusterData.nPixels, layer};
7170
}
72-
return result;
7371
}
7472

7573
template <o2::detectors::DetID::ID DetId, typename Consume>
@@ -108,8 +106,8 @@ GlobalMeasurement makeCylinderGlobalMeasurement(const DecodedCluster& decoded, u
108106
cosine * cosine * covariance.uu,
109107
cosine * covariance.uv,
110108
covariance.vv},
111-
std::hypot(decoded.global.x, decoded.global.y),
112-
std::atan2(decoded.global.y, decoded.global.x),
109+
0.f, // Radius and phi are computed after subtracting the beam position.
110+
0.f,
113111
clusterId};
114112
}
115113

@@ -124,8 +122,8 @@ GlobalMeasurement makeDiskGlobalMeasurement(const DecodedCluster& decoded, uint3
124122
decoded.global.z,
125123
{decoded.rowColumnCovariance.uu, decoded.rowColumnCovariance.uv, 0.f,
126124
decoded.rowColumnCovariance.vv, 0.f, 0.f},
127-
std::hypot(decoded.global.x, decoded.global.y),
128-
std::atan2(decoded.global.y, decoded.global.x),
125+
0.f, // Radius and phi are computed after subtracting the beam position.
126+
0.f,
129127
clusterId};
130128
}
131129

@@ -181,7 +179,7 @@ bool globalCovarianceIsPositiveSemidefinite(const GlobalCovariance3F& covariance
181179
bool decodedMeasurementIsValid(const GlobalMeasurement& global,
182180
const SurfaceMeasurement& local) noexcept
183181
{
184-
return globalCovarianceIsPositiveSemidefinite(global.covariance) &
182+
return globalCovarianceIsPositiveSemidefinite(global.covariance) &&
185183
covariance2DIsPositiveSemidefinite(local.covariance.uu, local.covariance.uv, local.covariance.vv);
186184
}
187185

@@ -264,11 +262,8 @@ void prepareSources(TimeFrame& frame, const SurfaceCatalogView& catalog,
264262
throw std::runtime_error(std::format("Invalid source-to-surface layer mapping source={}", owner.value()));
265263
}
266264
}
267-
if (!sources.empty()) {
268-
frame.setROFViews(sources.front().rofViews);
269-
}
270265
}
271-
void validateSource(const ClusterSourceInput& src, const o2::InteractionRecord& origin)
266+
void validateClusterRanges(const ClusterSourceInput& src)
272267
{
273268
int64_t expectedNext = 0;
274269
for (uint32_t r = 0; r < src.rofs.size(); ++r) {
@@ -286,13 +281,6 @@ void validateSource(const ClusterSourceInput& src, const o2::InteractionRecord&
286281
if (expectedNext != static_cast<int64_t>(src.clusters.size())) {
287282
throw std::runtime_error(std::format("Invalid ROF cluster range source={} rof={}", src.id.value(), static_cast<uint32_t>(src.rofs.size())));
288283
}
289-
290-
for (uint32_t r = 0; r < src.rofs.size(); ++r) {
291-
const auto built = computeROFIntervalBC(src.rofs[r].getBCData(), origin, src.timing, r);
292-
if (!built.ok()) {
293-
throw std::runtime_error(std::format("Invalid ROF timing: source={} rof={} timingError={}", src.id.value(), r, static_cast<int>(built.error)));
294-
}
295-
}
296284
}
297285
void appendCluster(TimeFrame& frame, const SurfaceCatalogView& catalog,
298286
const ClusterSourceInput& src, const DecodedCluster& decoded,
@@ -337,17 +325,17 @@ void appendCluster(TimeFrame& frame, const SurfaceCatalogView& catalog,
337325
clusterSizes[expectedSurface.value()].push_back(decoded.nPixels);
338326
externalIndices[expectedSurface.value()].push_back(externalIndex);
339327
}
340-
void bindSourceROFNavigation(TimeFrame& frame, const ClusterSourceInput& source,
341-
const std::vector<std::vector<int>>& boundaries)
328+
void storeSourceROFClusters(TimeFrame& frame, const ClusterSourceInput& source,
329+
const std::vector<std::vector<int>>& boundaries)
342330
{
343331
for (uint16_t layer = 0; layer < source.layerToSurface.size(); ++layer) {
344-
frame.setROFNavigation(source.layerToSurface[layer].value(), boundaries[layer], source.rofViews, layer);
332+
frame.setROFClusters(source.layerToSurface[layer].value(), boundaries[layer]);
345333
}
346334
}
347335
} // namespace detail
348336

349337
void loadTimeFrameSources(TimeFrame& frame, gsl::span<const ClusterSourceInput> sources,
350-
SurfaceCatalogView catalog, const o2::InteractionRecord& origin,
338+
SurfaceCatalogView catalog,
351339
std::vector<std::vector<uint32_t>>* externalIndicesBySurface,
352340
std::vector<std::vector<uint32_t>>* clusterSizesBySurface)
353341
{
@@ -356,7 +344,7 @@ void loadTimeFrameSources(TimeFrame& frame, gsl::span<const ClusterSourceInput>
356344
std::vector<std::vector<uint32_t>> clusterSizes(catalog.nSurfaces);
357345
bool hasMCInformation = false;
358346
for (const auto& source : sources) {
359-
detail::validateSource(source, origin);
347+
detail::validateClusterRanges(source);
360348
const auto load = [&](const auto& decode) {
361349
detail::loadDecodedSource(frame, catalog, source, decode, externalIndices, clusterSizes);
362350
};

Detectors/ITSMFT/common/tracking/src/Propagator.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ bool covarianceDiagonalsNonNegative(const SurfaceTrackState& state) noexcept
205205
// the retained TrackParametrizationWithError<float>::checkCovariance()
206206
// range-clamp values, and the same five constants
207207
// PropagatorBarrelOperations.cxx's post-propagate/rotate/update
208-
// sanitization (ADR 0008) enforces.
208+
// sanitization enforces.
209209
constexpr float kBarrelMaxDiagonal[5] = {o2::track::kCY2max, o2::track::kCZ2max, o2::track::kCSnp2max,
210210
o2::track::kCTgl2max, o2::track::kC1Pt2max};
211211

Detectors/ITSMFT/common/tracking/src/PropagatorBarrelOperations.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ void transportCovariance(SurfaceTrackState& state, const DenseMatrix5& jacobian)
9090
}
9191

9292
// Shared commit point for non-linRef rotate() and propagate(). It validates
93-
// and sanitizes the covariance (ADR 0008) on every exit, including dx == 0.
93+
// and sanitizes the covariance on every exit, including dx == 0.
9494
bool commit(SurfaceTrackState& destination, SurfaceTrackState& scratch) noexcept
9595
{
9696
sanitizeCovariance(scratch, kBarrelMaxDiagonal);

Detectors/ITSMFT/common/tracking/src/TimeFrame.cxx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,19 @@ void TimeFrame::setROFViews(RuntimeROFViews views) noexcept
203203
mUseUPC = false;
204204
}
205205

206-
void TimeFrame::setROFNavigation(std::size_t position, gsl::span<const int> boundaries,
207-
RuntimeROFViews views, uint16_t localLayer)
206+
void TimeFrame::setROFClusters(std::size_t position, gsl::span<const int> boundaries)
208207
{
209208
if (!mConfigurationValid || position >= mROFramesClusters.size()) {
210-
throw std::logic_error{"TimeFrame::setROFNavigation(): invalid or unconfigured surface position"};
209+
throw std::logic_error{"TimeFrame::setROFClusters(): invalid or unconfigured surface position"};
211210
}
212211
mROFramesClusters[position].assign(boundaries.begin(), boundaries.end());
212+
}
213+
214+
void TimeFrame::setROFViews(std::size_t position, RuntimeROFViews views, uint16_t localLayer)
215+
{
216+
if (!mConfigurationValid || position >= mROFViewsBySurface.size()) {
217+
throw std::logic_error{"TimeFrame::setROFViews(): invalid or unconfigured surface position"};
218+
}
213219
mROFViewsBySurface[position] = views;
214220
mROFLocalLayerBySurface[position] = localLayer;
215221
mUseUPC = false;

Detectors/ITSMFT/common/tracking/test/CombinedTrackingTestSupport.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ class CombinedTrackingPlan
178178
}
179179

180180
SurfaceCatalogView catalogView() const noexcept { return combinedCatalogView(); }
181-
void configureRofTables(const ClusterSourceInput& itsSource, const ClusterSourceInput& mftSource)
181+
void configureRofTables(const TestClusterSourceInput& itsSource, const TestClusterSourceInput& mftSource)
182182
{
183183
auto configure = [](auto& overlap, auto& vertex, auto& mask, const auto& timing, uint32_t nROFs, int layers) {
184184
o2::its::LayerTiming layerTiming{};

Detectors/ITSMFT/common/tracking/test/TrackingParameterTestSupport.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "ITSMFTTracking/Configuration.h"
1515
#include "ITSMFTTracking/IOUtils.h"
1616
#include "ITSMFTTracking/TimeFrame.h"
17+
#include "ITSMFTTracking/SurfaceTiming.h"
1718
#include <functional>
1819
#include "ITSMFTTracking/ITSMFTDetectorDefinitions.h"
1920

@@ -92,6 +93,9 @@ inline std::vector<TrackingParameters> referenceTrackingParameters(o2::detectors
9293
// Synthetic decoding is confined to tests. Exercise the same normalization
9394
// and ROF bookkeeping as production without constructing detector geometry.
9495
struct TestClusterSourceInput : ClusterSourceInput {
96+
// Fixture-owned timing is bound separately after cluster loading.
97+
ROFTimingConfig timing{};
98+
RuntimeROFViews rofViews{};
9599
std::function<DecodedCluster(const itsmft::CompClusterExt&, gsl::span<const unsigned char>::iterator&,
96100
const itsmft::TopologyDictionary*, uint32_t)>
97101
decode;
@@ -106,7 +110,7 @@ struct TestClusterSourceInput : ClusterSourceInput {
106110
};
107111

108112
inline void loadSources(TimeFrame& frame, const SurfaceCatalogView& catalog,
109-
gsl::span<const TestClusterSourceInput> sources, const o2::InteractionRecord& origin,
113+
gsl::span<const TestClusterSourceInput> sources, const o2::InteractionRecord&,
110114
std::vector<std::vector<uint32_t>>* indices = nullptr,
111115
std::vector<std::vector<uint32_t>>* sizes = nullptr, bool requireCompleteMapping = false)
112116
{
@@ -116,13 +120,21 @@ inline void loadSources(TimeFrame& frame, const SurfaceCatalogView& catalog,
116120
std::vector<std::vector<uint32_t>> clusterSizes(catalog.nSurfaces);
117121
bool hasMCInformation = false;
118122
for (const auto& source : sources) {
119-
detail::validateSource(source, origin);
123+
detail::validateClusterRanges(source);
120124
detail::loadDecodedSource(frame, catalog, source, [&](const auto& cluster, auto& patterns) {
121125
const auto index = static_cast<uint32_t>(&cluster - source.clusters.data());
122126
return source.decode(cluster, patterns, source.dictionary, index); }, externalIndices, clusterSizes);
123127
hasMCInformation |= source.labels != nullptr;
124128
}
125129
frame.setHasMCInformation(hasMCInformation);
130+
if (!sources.empty()) {
131+
frame.setROFViews(sources.front().rofViews);
132+
for (const auto& source : sources) {
133+
for (uint16_t layer = 0; layer < source.layerToSurface.size(); ++layer) {
134+
frame.setROFViews(source.layerToSurface[layer].value(), source.rofViews, layer);
135+
}
136+
}
137+
}
126138
if (indices != nullptr) {
127139
*indices = std::move(externalIndices);
128140
}

0 commit comments

Comments
 (0)