Skip to content

Commit 69dde8b

Browse files
committed
Unify application of systematics
1 parent f4a50d7 commit 69dde8b

13 files changed

Lines changed: 114 additions & 80 deletions

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ TrackingPlan getTrackingPlan(o2::detectors::DetID::ID detId, Type mode);
258258
namespace o2::itsmft::tracking
259259
{
260260

261-
/// MFT uses o2::itsmft::TrackerParamConfig; ITS keeps its legacy parameter type.
261+
/// Detector-specific entry points for the common CA configuration.
262262
template <o2::detectors::DetID::ID DetId>
263263
struct TrackerParamRef;
264264

@@ -271,7 +271,7 @@ struct TrackerParamRef<o2::detectors::DetID::MFT> {
271271

272272
template <>
273273
struct TrackerParamRef<o2::detectors::DetID::ITS> {
274-
using Type = o2::its::TrackerParamConfig;
274+
using Type = o2::itsmft::ITSCommonCATrackerParam;
275275
static const Type& get() { return Type::Instance(); }
276276
static constexpr int nLayers() { return ITSNLayers; }
277277
};

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ struct DecodedCluster {
5151
// ITS geometry supplies its cylindrical tracking frame here. Disk
5252
// projection uses global coordinates directly.
5353
SurfaceFramePoint cylinderFrame{};
54-
// ALPIDE local row/column covariance. The detector projection determines
55-
// which normalized axes these values describe.
54+
// Intrinsic ALPIDE local row/column covariance, without alignment systematics.
55+
// The shared loader adds configured systematics before detector projection.
5656
SurfaceCovariance2F rowColumnCovariance{};
5757
uint32_t nPixels{0};
5858
int layer{-1};
@@ -127,7 +127,6 @@ struct ClusterSourceInput {
127127
const o2::dataformats::MCTruthContainer<o2::MCCompLabel>* labels{nullptr};
128128
gsl::span<const LayerId> layerToSurface{};
129129
ROFTimingConfig timing{};
130-
bool applySysErrors{true};
131130
RuntimeROFViews rofViews{};
132131
};
133132

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ struct ITSCommonCATrackerParam : public o2::conf::ConfigurableParamHelper<ITSCom
5757
float diamondPos[3] = {0.f, 0.f, 0.f}; // Diamond vertex position when useDiamond is set.
5858
float pvRes = -1.f; // Diamond-vertex PV resolution; <=0 keeps the default.
5959
uint16_t holeLayerMask = 0; // Detector layers that may be absent from accepted tracks.
60+
float sysErr2Row[tracking::ITSNLayers] = {0}; // Additional sensor-row variance for cluster covariance and candidate windows (cm^2).
61+
float sysErr2Col[tracking::ITSNLayers] = {0}; // Additional sensor-column variance for cluster covariance and candidate windows (cm^2).
6062

6163
/// Number of tbb::task_arena threads for the ITS common-CA tracker.
6264
/// This dedicated field is separate from the legacy ITS configuration.
@@ -87,8 +89,8 @@ struct TrackerParamConfig : public o2::conf::ConfigurableParamHelper<TrackerPara
8789
int maxHolesIter[o2::itsmft::tracking::MaxIter] = {}; // Maximum missing internal layers per iteration.
8890
uint16_t holeLayerMask = 0; // Detector layers that may be absent from accepted tracks.
8991
float minPtIterLgt[o2::itsmft::tracking::MaxIter * (MaxTrackLength - MinTrackLength + 1)] = {}; // Async minimum pT by track length; <=0 keeps preset.
90-
float sysErr2Row[getNLayers()] = {0}; // Systematic sensor-row variance for candidate windows (cm^2).
91-
float sysErr2Col[getNLayers()] = {0}; // Systematic sensor-column variance for candidate windows (cm^2).
92+
float sysErr2Row[getNLayers()] = {0}; // Additional sensor-row variance for cluster covariance and candidate windows (cm^2).
93+
float sysErr2Col[getNLayers()] = {0}; // Additional sensor-column variance for cluster covariance and candidate windows (cm^2).
9294
float maxChi2ClusterAttachment = -1.f;
9395
float maxChi2NDF = -1.f;
9496
float nSigmaCut = -1.f;

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,20 @@ constexpr bool iequals(std::string_view a, std::string_view b)
3333
return std::equal(a.begin(), a.end(), b.begin(), b.end(),
3434
[](char x, char y) { return std::tolower(x) == std::tolower(y); });
3535
}
36+
37+
template <typename Config>
38+
void resolveSystematicErrors(o2::itsmft::DetectorParameters& parameters, const Config& config)
39+
{
40+
for (size_t layer = 0; layer < std::size(config.sysErr2Row); ++layer) {
41+
const auto row = config.sysErr2Row[layer];
42+
const auto col = config.sysErr2Col[layer];
43+
if (row < 0.f || col < 0.f) {
44+
throw std::invalid_argument(std::format("{}.sysErr2Row/Col[{}] must be finite nonnegative variances", config.getName(), layer));
45+
}
46+
parameters.SystError2Row[layer] = row;
47+
parameters.SystError2Col[layer] = col;
48+
}
49+
}
3650
} // namespace
3751

3852
namespace o2::itsmft
@@ -202,6 +216,7 @@ TrackingPlan getTrackingPlan(detectors::DetID::ID detId, Type mode)
202216
auto& trackParams = plan.iterations;
203217
if (detId == detectors::DetID::ITS) {
204218
const auto& tc = ITSCommonCATrackerParam::Instance();
219+
resolveSystematicErrors(plan.detector, tc);
205220
if (mode == Async) {
206221
trackParams.assign(3, defaults);
207222
trackParams[1].TrackletMinPt = 0.2f;
@@ -338,9 +353,8 @@ TrackingPlan getTrackingPlan(detectors::DetID::ID detId, Type mode)
338353
}
339354

340355
plan.execution = {tc.maxMemory, tc.dropTFUponFailure};
356+
resolveSystematicErrors(plan.detector, tc);
341357
for (int i{0}; i < TrackerParamConfig<detectors::DetID::MFT>::getNLayers(); ++i) {
342-
plan.detector.SystError2Row[i] = tc.sysErr2Row[i] > 0 ? tc.sysErr2Row[i] : plan.detector.SystError2Row[i];
343-
plan.detector.SystError2Col[i] = tc.sysErr2Col[i] > 0 ? tc.sysErr2Col[i] : plan.detector.SystError2Col[i];
344358
plan.detector.AddTimeError[i] = tc.addTimeError[i];
345359
}
346360
plan.detector.ColBins = tc.LUTbinsU > 0 ? tc.LUTbinsU : plan.detector.ColBins;

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

Lines changed: 15 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -26,45 +26,11 @@
2626
namespace
2727
{
2828

29-
/// Return whether cluster-decoding systematic errors are configured for `DetId`.
30-
/// ITS is a no-op; MFT reads its live tracker configuration.
31-
template <o2::detectors::DetID::ID DetId>
32-
bool shouldApplySysErrors()
33-
{
34-
if constexpr (DetId == o2::detectors::DetID::ITS) {
35-
return false;
36-
} else {
37-
const auto& conf = o2::itsmft::tracking::TrackerParamRef<DetId>::get();
38-
for (int il = 0; il < o2::itsmft::tracking::TrackerParamRef<DetId>::nLayers(); il++) {
39-
if (conf.sysErr2Row[il] > 0.f || conf.sysErr2Col[il] > 0.f) {
40-
return true;
41-
}
42-
}
43-
return false;
44-
}
45-
}
46-
47-
/// Add configured systematic-error corrections to `sigma2Row` and `sigma2Col`.
48-
/// ITS is a no-op.
49-
template <o2::detectors::DetID::ID DetId>
50-
void addSysErrors(int layerId, float& sigma2Row, float& sigma2Col)
51-
{
52-
if constexpr (DetId == o2::detectors::DetID::ITS) {
53-
(void)layerId;
54-
(void)sigma2Row;
55-
(void)sigma2Col;
56-
} else {
57-
const auto& conf = o2::itsmft::tracking::TrackerParamRef<DetId>::get();
58-
sigma2Row += conf.sysErr2Row[layerId];
59-
sigma2Col += conf.sysErr2Col[layerId];
60-
}
61-
}
62-
6329
template <o2::detectors::DetID::ID DetId, typename GeomT>
6430
o2::itsmft::tracking::DecodedCluster decodeCluster(
6531
GeomT* geom, const o2::itsmft::CompClusterExt& cluster,
6632
gsl::span<const unsigned char>::iterator& patterns,
67-
const o2::itsmft::TopologyDictionary* dict, bool applySysErrors)
33+
const o2::itsmft::TopologyDictionary* dict)
6834
{
6935
o2::itsmft::tracking::DecodedCluster result;
7036
if (dict == nullptr) {
@@ -84,11 +50,8 @@ o2::itsmft::tracking::DecodedCluster decodeCluster(
8450
}
8551

8652
const auto clusterData = o2::itsmft::ioutils::extractClusterData(cluster, patterns, dict);
87-
float sigma2Row = clusterData.sig2Row;
88-
float sigma2Col = clusterData.sig2Col;
89-
if (applySysErrors && shouldApplySysErrors<DetId>()) {
90-
addSysErrors<DetId>(layer, sigma2Row, sigma2Col);
91-
}
53+
const float sigma2Row = clusterData.sig2Row;
54+
const float sigma2Col = clusterData.sig2Col;
9255

9356
if constexpr (DetId == o2::detectors::DetID::ITS) {
9457
const auto trkXYZ = geom->getMatrixT2L(sensorID) ^ clusterData.coordinates;
@@ -118,7 +81,7 @@ void decodeDetectorSource(const o2::itsmft::tracking::ClusterSourceInput& source
11881
geometry->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G));
11982
}
12083
consume([&](const auto& cluster, auto& patterns) {
121-
return decodeCluster<DetId>(geometry, cluster, patterns, source.dictionary, source.applySysErrors);
84+
return decodeCluster<DetId>(geometry, cluster, patterns, source.dictionary);
12285
});
12386
}
12487

@@ -342,14 +305,21 @@ void appendCluster(TimeFrame& frame, const SurfaceCatalogView& catalog,
342305
const auto expectedSurface = src.layerToSurface[decoded.layer];
343306
const auto& surfaceDescriptor = catalog.getSurface(expectedSurface);
344307
const auto localClusterId = static_cast<uint32_t>(frame.getGlobalMeasurements(expectedSurface).size());
308+
// Apply alignment systematics once, for both detectors, before projecting
309+
// either covariance. Use the same resolved configuration as search windows,
310+
// indexed by the mapped surface (not the detector-local layer).
311+
auto corrected = decoded;
312+
const auto& configuration = frame.getDetectorConfiguration();
313+
corrected.rowColumnCovariance.uu += configuration.systError2Row.empty() ? 0.f : configuration.systError2Row.at(expectedSurface.value());
314+
corrected.rowColumnCovariance.vv += configuration.systError2Col.empty() ? 0.f : configuration.systError2Col.at(expectedSurface.value());
345315
GlobalMeasurement global;
346316
SurfaceMeasurement measurement;
347317
if (surfaceDescriptor.kind == SurfaceKind::Cylinder) {
348-
global = makeCylinderGlobalMeasurement(decoded, localClusterId);
349-
measurement = makeCylinderSurfaceMeasurement(decoded);
318+
global = makeCylinderGlobalMeasurement(corrected, localClusterId);
319+
measurement = makeCylinderSurfaceMeasurement(corrected);
350320
} else {
351-
global = makeDiskGlobalMeasurement(decoded, localClusterId);
352-
measurement = makeDiskSurfaceMeasurement(decoded);
321+
global = makeDiskGlobalMeasurement(corrected, localClusterId);
322+
measurement = makeDiskSurfaceMeasurement(corrected);
353323
}
354324
if (!decodedMeasurementIsValid(global, measurement)) {
355325
throw std::runtime_error(std::format("Malformed cluster loading input source={} rof={} clusterIndex={}", src.id.value(), r, externalIndex));

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,14 @@ inline std::vector<TrackingParameters> referenceTrackingParameters(o2::detectors
9393
// and ROF bookkeeping as production without constructing detector geometry.
9494
struct TestClusterSourceInput : ClusterSourceInput {
9595
std::function<DecodedCluster(const itsmft::CompClusterExt&, gsl::span<const unsigned char>::iterator&,
96-
const itsmft::TopologyDictionary*, uint32_t, bool)>
96+
const itsmft::TopologyDictionary*, uint32_t)>
9797
decode;
9898

9999
template <typename Decoder>
100100
void setDecoder(const Decoder& decoder)
101101
{
102-
decode = [&decoder](const auto& cluster, auto& patterns, const auto* dictionary, uint32_t index, bool sysErrors) {
103-
return decoder.decode(cluster, patterns, dictionary, index, sysErrors);
102+
decode = [&decoder](const auto& cluster, auto& patterns, const auto* dictionary, uint32_t index) {
103+
return decoder.decode(cluster, patterns, dictionary, index);
104104
};
105105
}
106106
};
@@ -119,7 +119,7 @@ inline void loadSources(TimeFrame& frame, const SurfaceCatalogView& catalog,
119119
detail::validateSource(source, origin);
120120
detail::loadDecodedSource(frame, catalog, source, [&](const auto& cluster, auto& patterns) {
121121
const auto index = static_cast<uint32_t>(&cluster - source.clusters.data());
122-
return source.decode(cluster, patterns, source.dictionary, index, source.applySysErrors); }, externalIndices, clusterSizes);
122+
return source.decode(cluster, patterns, source.dictionary, index); }, externalIndices, clusterSizes);
123123
hasMCInformation |= source.labels != nullptr;
124124
}
125125
frame.setHasMCInformation(hasMCInformation);
@@ -153,7 +153,6 @@ void loadTimeFrameSource(
153153
o2::detectors::DetID::ID detector,
154154
gsl::span<const LayerId> layerToSurface,
155155
SurfaceCatalogView catalog,
156-
bool applySysErrors = true,
157156
std::vector<std::vector<uint32_t>>* externalIndicesBySurface = nullptr,
158157
std::vector<std::vector<uint32_t>>* clusterSizesBySurface = nullptr)
159158
{
@@ -169,7 +168,6 @@ void loadTimeFrameSource(
169168
source.layerToSurface = layerToSurface;
170169
source.timing = timing;
171170
source.setDecoder(decoder);
172-
source.applySysErrors = applySysErrors;
173171
source.rofViews = frame.getROFViews();
174172
loadTimeFrameSources(frame, gsl::span<const TestClusterSourceInput>{&source, 1}, catalog, origin,
175173
externalIndicesBySurface, clusterSizesBySurface);

Detectors/ITSMFT/common/tracking/test/testCombinedTrackingComposition.cxx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,7 @@ class PrescribedDecoder
103103
const CompClusterExt& cluster,
104104
gsl::span<const unsigned char>::iterator& patterns,
105105
const TopologyDictionary* dictionary,
106-
uint32_t externalIndex,
107-
bool) const
106+
uint32_t externalIndex) const
108107
{
109108
const auto clusterData = o2::itsmft::ioutils::extractClusterData(cluster, patterns, dictionary);
110109
o2::itsmft::tracking::DecodedCluster result;

Detectors/ITSMFT/common/tracking/test/testComputeLayerCellsOrchestration.cxx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class NeverDecodedDecoder
8484

8585
o2::itsmft::tracking::DecodedCluster decode(
8686
const CompClusterExt&, gsl::span<const unsigned char>::iterator&, const TopologyDictionary*,
87-
uint32_t, bool) const
87+
uint32_t) const
8888
{
8989
return {};
9090
}
@@ -117,8 +117,7 @@ class FixedMeasurementDecoder
117117
const CompClusterExt& cluster,
118118
gsl::span<const unsigned char>::iterator&,
119119
const TopologyDictionary*,
120-
uint32_t,
121-
bool) const
120+
uint32_t) const
122121
{
123122
o2::itsmft::tracking::DecodedCluster result;
124123
const int layer = cluster.getSensorID();

Detectors/ITSMFT/common/tracking/test/testComputeLayerTrackletsOrchestration.cxx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,7 @@ class PrescribedDecoder
105105
const CompClusterExt& cluster,
106106
gsl::span<const unsigned char>::iterator& patterns,
107107
const TopologyDictionary* dictionary,
108-
uint32_t externalIndex,
109-
bool) const
108+
uint32_t externalIndex) const
110109
{
111110
const auto clusterData = o2::itsmft::ioutils::extractClusterData(cluster, patterns, dictionary);
112111
o2::itsmft::tracking::DecodedCluster result;

Detectors/ITSMFT/common/tracking/test/testGenericTrack.cxx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,7 @@ class FakeClusterDecoder
210210
const CompClusterExt& cluster,
211211
gsl::span<const unsigned char>::iterator& patterns,
212212
const TopologyDictionary* dict,
213-
uint32_t,
214-
bool applySysErrors) const
213+
uint32_t) const
215214
{
216215
const auto clusterData = o2::itsmft::ioutils::extractClusterData(cluster, patterns, dict);
217216
o2::itsmft::tracking::DecodedCluster result;
@@ -472,8 +471,7 @@ class LegacyLikeDecoder
472471
const CompClusterExt& cluster,
473472
gsl::span<const unsigned char>::iterator& patterns,
474473
const TopologyDictionary* dict,
475-
uint32_t,
476-
bool applySysErrors) const
474+
uint32_t) const
477475
{
478476
const auto clusterData = o2::itsmft::ioutils::extractClusterData(cluster, patterns, dict);
479477
o2::itsmft::tracking::DecodedCluster result;
@@ -537,7 +535,7 @@ struct TimeFrameFixture {
537535
const auto patterns = makePatternBytes(clusters.size());
538536
const std::vector<ROFRecord> rofs{ROFRecord{{100, 5}, 0, 0, 1}};
539537
test::loadTimeFrameSource(tf, decoder, origin, timing, clusters, patterns, rofs, &dict(), nullptr, o2::detectors::DetID::ITS,
540-
gsl::span<const LayerId>{layerMapping}, tf.getDetectorConfiguration().getSurfaceCatalog(), true,
538+
gsl::span<const LayerId>{layerMapping}, tf.getDetectorConfiguration().getSurfaceCatalog(),
541539
&externalIndicesBySurface, &clusterSizesBySurface);
542540
}
543541
};

0 commit comments

Comments
 (0)