Project
Loading...
Searching...
No Matches
testTrackletFinding.cxx
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#define BOOST_TEST_MODULE ITSMFT TrackletFinding
13#define BOOST_TEST_MAIN
14#define BOOST_TEST_DYN_LINK
15
16#include <algorithm>
17#include <array>
18#include <cmath>
19#include <limits>
20#include <utility>
21
22#include <boost/test/unit_test.hpp>
23
24#include <TGeoGlobalMagField.h>
25
28#include "Field/MagneticField.h"
33
35
37using namespace o2::itsmft;
38using namespace o2::itsmft::tracking;
39
42 {
43 if (!TGeoGlobalMagField::Instance()->GetField()) {
44 TGeoGlobalMagField::Instance()->SetField(o2::field::MagneticField::createNominalField(5, true));
45 TGeoGlobalMagField::Instance()->Lock();
46 }
47 }
48};
49
51
56
57namespace
58{
59
60constexpr float Bz = 0.5f;
61
62void configureCylinderIndex(IndexTableUtilsCore& index, const DetectorParameters& parameters)
63{
64 std::array<SurfaceChartRange, ITSNLayers> ranges;
65 for (int layer = 0; layer < ITSNLayers; ++layer) {
66 ranges[layer] = kITSSurfaces[layer].chartRange;
67 }
68 BOOST_REQUIRE(configureIndexTableUtils(index, parameters, ITSNLayers, SurfaceKind::Cylinder, ranges));
69}
70
71o2::its::TrackingFrameInfo makeBarrelHit(float xTF, float alpha, float y, float z, float sigma2Y = 1.e-4f, float sigma2Z = 1.e-4f)
72{
73 return o2::its::TrackingFrameInfo{xTF, y, z, xTF, alpha, {y, z}, {sigma2Y, 0.f, sigma2Z}};
74}
75
76o2::its::TrackingFrameInfo makeDiskHit(float z, float x, float y, float sigma2X = 1.e-2f, float sigma2Y = 1.e-2f)
77{
78 return o2::its::TrackingFrameInfo{x, y, z, 0.f, 0.f, {x, y}, {sigma2X, 0.f, sigma2Y}};
79}
80
81o2::its::Vertex makeVertex(float x, float y, float z,
82 float sigma2X, float sigma2Y, float sigma2Z,
83 unsigned short contributors = 1)
84{
85 const float position[3]{x, y, z};
86 const float covariance[6]{sigma2X, 0.f, sigma2Y, 0.f, 0.f, sigma2Z};
87 return o2::its::Vertex{position, covariance, contributors, 1.f};
88}
89
90GlobalMeasurement makeGlobalCluster(float x, float y, float z, int id = 0)
91{
92 GlobalMeasurement measurement{};
93 measurement.position = {x, y, z};
94 measurement.radius = std::hypot(x, y);
95 measurement.phi = o2::its::math_utils::computePhi(x, y);
96 measurement.clusterId = static_cast<uint32_t>(id);
97 return measurement;
98}
99
100GlobalMeasurement makeMeasurement(float x, float y, float z, float uu = 1.e-4f, float vv = 1.e-4f, float uv = 0.f)
101{
102 GlobalMeasurement measurement{};
103 measurement.position = {x, y, z};
104 measurement.radius = std::hypot(x, y);
105 measurement.covariance = {uu, uv, 0.f, vv, 0.f, 0.f};
106 return measurement;
107}
108
109GlobalMeasurement makeMeasurement(const GlobalMeasurement& cluster, float uu = 1.e-4f, float vv = 1.e-4f, float uv = 0.f)
110{
111 auto measurement = cluster;
112 measurement.covariance = {uu, uv, 0.f, vv, 0.f, 0.f};
113 return measurement;
114}
115
116TrackletProjectionCache makeCylinderProjectionCache(int fromLayer, int toLayer, float fromRadius, float toRadius,
117 float targetMinR, float targetMaxR, float sourcePositionResolution,
118 float edgeMSAngle, float edgePhiCut)
119{
120 return {fromLayer, toLayer, fromRadius, toRadius, targetMinR, targetMaxR, 0.f, 0.f,
121 sourcePositionResolution, edgeMSAngle, edgePhiCut};
122}
123
124TrackletProjectionCache makeDiskProjectionCache(int fromLayer, int toLayer, float fromRadius,
125 float, float targetMinZ, float targetMaxZ,
126 float edgeMSAngle, float edgePhiCut)
127{
128 return {fromLayer, toLayer, fromRadius, 0.f, 0.f, 0.f, targetMinZ, targetMaxZ,
129 0.f, edgeMSAngle, edgePhiCut};
130}
131
132// CandidateFinding exposes one descriptor-selected projection operation.
133// Keep the numerical fixtures readable without exporting coordinate leaves.
134bool projectCylinderSearchWindow(const GlobalMeasurement& sourceMeasurement,
135 const GlobalMeasurement&,
136 const o2::its::Vertex& vertex,
137 const TrackletProjectionCache& edgeCache,
138 const o2::itsmft::IndexTableUtilsCore& indexUtils,
141{
142 return projectTrackletSearchWindow(sourceMeasurement, vertex, 0.f, SurfaceKind::Cylinder,
143 edgeCache, indexUtils, params.nSigmaCut, out);
144}
145
146bool projectDiskSearchWindow(const GlobalMeasurement& sourceMeasurement,
147 const GlobalMeasurement&,
148 const o2::its::Vertex& vertex,
149 const TrackletProjectionCache& edgeCache,
150 const o2::itsmft::IndexTableUtilsCore& indexUtils,
153{
154 return projectTrackletSearchWindow(sourceMeasurement, vertex, 0.f, SurfaceKind::Disk,
155 edgeCache, indexUtils, params.nSigmaCut, out);
156}
157
158void setDiskLookup(IndexTableUtilsCore& indexUtils, const ReferenceTrackingParameters& params,
159 float radialMin = 0.1f, float radialMax = 20.f)
160{
161 std::array<float, IndexTableUtilsCore::MaxLayers> minima{};
162 std::array<float, IndexTableUtilsCore::MaxLayers> maxima{};
163 minima.fill(radialMin);
164 maxima.fill(radialMax);
165 indexUtils.setIndexTableParams(IndexTableCoordType::PhiR, params.RowBins, params.ColBins,
166 0.f, o2::constants::math::TwoPI, minima, maxima);
167}
168
169void checkSearchWindowEqual(const TrackletSearchWindow& lhs, const TrackletSearchWindow& rhs)
170{
171 BOOST_CHECK_EQUAL(lhs.bins.x, rhs.bins.x);
172 BOOST_CHECK_EQUAL(lhs.bins.y, rhs.bins.y);
173 BOOST_CHECK_EQUAL(lhs.bins.z, rhs.bins.z);
174 BOOST_CHECK_EQUAL(lhs.bins.w, rhs.bins.w);
175 BOOST_CHECK_EQUAL(lhs.sourceReferenceCoordinate, rhs.sourceReferenceCoordinate);
176 BOOST_CHECK_EQUAL(lhs.sourceProjectedCoordinate, rhs.sourceProjectedCoordinate);
177 BOOST_CHECK_EQUAL(lhs.slope, rhs.slope);
178 BOOST_CHECK_EQUAL(lhs.varianceConstant, rhs.varianceConstant);
179 BOOST_CHECK_EQUAL(lhs.varianceLinear, rhs.varianceLinear);
180 BOOST_CHECK_EQUAL(lhs.varianceQuadratic, rhs.varianceQuadratic);
181 BOOST_CHECK_EQUAL(lhs.phiPrediction, rhs.phiPrediction);
182 BOOST_CHECK_EQUAL(lhs.phiVariance, rhs.phiVariance);
183}
184
185std::pair<float, float> evaluateSearchWindowAt(const TrackletSearchWindow& window, float targetReferenceCoordinate)
186{
187 const float delta = targetReferenceCoordinate - window.sourceReferenceCoordinate;
188 return {window.sourceProjectedCoordinate + window.slope * delta,
189 window.varianceConstant + delta * (window.varianceLinear + delta * window.varianceQuadratic)};
190}
191
193{
194 (void)kind;
196 out.trackletMinPt = params.TrackletMinPt;
197 out.nSigmaCut = params.NSigmaCut;
198 out.maxChi2ClusterAttachment = params.MaxChi2ClusterAttachment;
199 out.maxChi2NDF = params.MaxChi2NDF;
200 out.pvResolution = params.PVres;
201 return out;
202}
203
204} // namespace
205
206BOOST_AUTO_TEST_CASE(BindingCopiesEveryFieldToTheCorrectSlot)
207{
208 // Distinct sentinel per field so a field-swap bug in the binding is caught.
210 legacy.TrackletMinPt = 1.11f;
211 legacy.NSigmaCut = 3.33f;
212 legacy.MaxChi2ClusterAttachment = 4.44f;
213 legacy.MaxChi2NDF = 5.55f;
214 legacy.PVres = 8.88f;
215
216 const auto barrel = makeKernelParameters(legacy, SurfaceKind::Cylinder);
217 BOOST_CHECK_CLOSE(barrel.trackletMinPt, 1.11f, 1e-6);
218 BOOST_CHECK_CLOSE(barrel.nSigmaCut, 3.33f, 1e-6);
219 BOOST_CHECK_CLOSE(barrel.maxChi2ClusterAttachment, 4.44f, 1e-6);
220 BOOST_CHECK_CLOSE(barrel.maxChi2NDF, 5.55f, 1e-6);
221 BOOST_CHECK_CLOSE(barrel.pvResolution, 8.88f, 1e-6);
222 BOOST_CHECK(barrel.isValid());
223
224 const auto disk = makeKernelParameters(legacy, SurfaceKind::Disk);
225 BOOST_CHECK_CLOSE(disk.trackletMinPt, 1.11f, 1e-6);
226 BOOST_CHECK_CLOSE(disk.nSigmaCut, 3.33f, 1e-6);
227 BOOST_CHECK_CLOSE(disk.maxChi2ClusterAttachment, 4.44f, 1e-6);
228 BOOST_CHECK_CLOSE(disk.maxChi2NDF, 5.55f, 1e-6);
229 BOOST_CHECK(disk.isValid());
230}
231
232BOOST_AUTO_TEST_CASE(CylinderProjectSearchWindowUsesCandidateRadiusAndBoundsTheFullTargetInterval)
233{
235 legacy.PVres = 0.f;
236 const auto params = makeKernelParameters(legacy, SurfaceKind::Cylinder);
237 BOOST_REQUIRE(params.isValid());
238
239 IndexTableUtilsCore indexUtils;
240 configureCylinderIndex(indexUtils, legacy);
241
242 const auto source = makeGlobalCluster(2.f, 0.f, 0.5f);
243 const auto sourceMeasurement = makeMeasurement(source);
244 const auto vertex = makeVertex(0.f, 0.f, 0.f, 1.e-4f, 1.e-4f, 4.e-4f, 4);
245 const auto state = makeCylinderProjectionCache(0, 3, 2.f, 4.f, 3.8f, 4.2f, 5.e-4f, 2.e-3f, 0.08f);
246
247 TrackletSearchWindow window{};
248 BOOST_REQUIRE((projectCylinderSearchWindow(
249 sourceMeasurement, source, vertex, state, indexUtils, params, window)));
250
251 const float tanLambda = (source.z - vertex.getZ()) / source.radius;
252 const float targetMeanRadius = 0.5f * (state.targetMinR + state.targetMaxR);
253 const float deltaRadius = targetMeanRadius - source.radius;
254 const float zAtTargetMeanR = tanLambda * deltaRadius + source.z;
255 const float projectionScale = 1.f + deltaRadius / source.radius;
256 const float originScale = projectionScale - 1.f;
257 const float sourceCoordinateVariance = o2::its::math_utils::Sq(state.sourcePositionResolution);
258 const float varianceZ =
259 o2::its::math_utils::Sq(projectionScale) * sourceCoordinateVariance +
260 o2::its::math_utils::Sq(tanLambda * projectionScale) * sourceCoordinateVariance +
261 o2::its::math_utils::Sq(originScale) * vertex.getSigmaZ2() +
262 o2::its::math_utils::Sq(deltaRadius * state.edgeMSAngle);
263 const auto predictionAndVarianceAt = [&](float radius) {
264 const float deltaR = radius - source.radius;
265 const float scale = 1.f + deltaR / source.radius;
266 const float origin = scale - 1.f;
267 const float candidateVariance =
268 o2::its::math_utils::Sq(scale) * sourceCoordinateVariance +
269 o2::its::math_utils::Sq(tanLambda * scale) * sourceCoordinateVariance +
270 o2::its::math_utils::Sq(origin) * vertex.getSigmaZ2() +
271 o2::its::math_utils::Sq(deltaR * state.edgeMSAngle);
272 return std::pair{source.z + tanLambda * deltaR, candidateVariance};
273 };
274 const auto [minPrediction, minVariance] = predictionAndVarianceAt(state.targetMinR);
275 const auto [maxPrediction, maxVariance] = predictionAndVarianceAt(state.targetMaxR);
276 const float lowerBound = std::min(minPrediction - params.nSigmaCut * std::sqrt(minVariance),
277 maxPrediction - params.nSigmaCut * std::sqrt(maxVariance));
278 const float upperBound = std::max(minPrediction + params.nSigmaCut * std::sqrt(minVariance),
279 maxPrediction + params.nSigmaCut * std::sqrt(maxVariance));
280 const auto directBins = getBinsPhiColumn(source.phi, state.toLayer, 0.5f * (lowerBound + upperBound),
281 0.5f * (upperBound - lowerBound), state.edgePhiCut, indexUtils);
282
283 BOOST_CHECK_EQUAL(window.bins.x, directBins.x);
284 BOOST_CHECK_EQUAL(window.bins.y, directBins.y);
285 BOOST_CHECK_EQUAL(window.bins.z, directBins.z);
286 BOOST_CHECK_EQUAL(window.bins.w, directBins.w);
287 const auto [midpointPrediction, midpointVariance] = evaluateSearchWindowAt(window, targetMeanRadius);
288 BOOST_CHECK_EQUAL(midpointPrediction, zAtTargetMeanR);
289 BOOST_CHECK_CLOSE_FRACTION(midpointVariance, varianceZ, 1.e-6f);
290 const auto [evaluatedMinPrediction, evaluatedMinVariance] = evaluateSearchWindowAt(window, state.targetMinR);
291 BOOST_CHECK_EQUAL(evaluatedMinPrediction, minPrediction);
292 BOOST_CHECK_CLOSE_FRACTION(evaluatedMinVariance, minVariance, 1.e-6f);
293 const auto [evaluatedMaxPrediction, evaluatedMaxVariance] = evaluateSearchWindowAt(window, state.targetMaxR);
294 BOOST_CHECK_EQUAL(evaluatedMaxPrediction, maxPrediction);
295 BOOST_CHECK_CLOSE_FRACTION(evaluatedMaxVariance, maxVariance, 1.e-6f);
296
297 TrackletSearchWindow beamUncertaintyWindow{};
298 BOOST_REQUIRE(projectTrackletSearchWindow(sourceMeasurement, vertex, 1.e-3f,
299 SurfaceKind::Cylinder, state, indexUtils, params.nSigmaCut,
300 beamUncertaintyWindow));
301 const auto [beamPrediction, beamVariance] = evaluateSearchWindowAt(beamUncertaintyWindow, targetMeanRadius);
302 BOOST_CHECK_EQUAL(beamPrediction, zAtTargetMeanR);
303 BOOST_CHECK_CLOSE_FRACTION(beamVariance,
304 varianceZ + o2::its::math_utils::Sq(tanLambda * originScale) * 1.e-3f, 1.e-6f);
305
306 legacy.PVres = 0.025f;
307 const auto differentConfiguredPVParams = makeKernelParameters(legacy, SurfaceKind::Cylinder);
308 BOOST_REQUIRE(differentConfiguredPVParams.isValid());
309 TrackletSearchWindow differentConfiguredPVWindow{};
310 BOOST_REQUIRE((projectCylinderSearchWindow(
311 sourceMeasurement, source, vertex, state, indexUtils, differentConfiguredPVParams, differentConfiguredPVWindow)));
312 checkSearchWindowEqual(differentConfiguredPVWindow, window);
313}
314
315BOOST_AUTO_TEST_CASE(DiskProjectSearchWindowBuildsPeriodicPhiRCoordinates)
316{
318 const auto params = makeKernelParameters(legacy, SurfaceKind::Disk);
319 BOOST_REQUIRE(params.isValid());
320
321 IndexTableUtilsCore indexUtils;
322 setDiskLookup(indexUtils, legacy);
323
324 constexpr int fromLayer = 1;
325 constexpr int toLayer = 4; // deliberately skipped/nonadjacent edge
326 const float fromZ = kMFTSurfaces[fromLayer].referenceCoordinate;
327 const float toZ = kMFTSurfaces[toLayer].referenceCoordinate;
328 const auto source = makeGlobalCluster(1.2f, 0.7f, fromZ);
329 const auto sourceMeasurement = makeMeasurement(source, 2.e-4f, 3.e-4f);
330 const auto vertex = makeVertex(0.01f, -0.02f, 0.1f, 4.e-4f, 5.e-4f, 0.04f, 3);
331 const auto state = makeDiskProjectionCache(fromLayer, toLayer, 2.f, fromZ, toZ, toZ, 3.e-3f, 0.04f);
332
333 TrackletSearchWindow window{};
334 BOOST_REQUIRE((projectDiskSearchWindow(
335 sourceMeasurement, source, vertex, state, indexUtils, params, window)));
336
337 const float slope = source.radius / (source.z - vertex.getZ());
338 const float deltaZ = toZ - source.z;
339 const float expectedRadius = source.radius + slope * deltaZ;
340 const float radialScale = expectedRadius / source.radius;
341 const float expectedX = radialScale * source.x;
342 const float expectedY = radialScale * source.y;
343 const float projectionScale = 1.f + deltaZ / (source.z - vertex.getZ());
344 const float originScale = projectionScale - 1.f;
345 const float sourceCoordinateVariance = o2::its::math_utils::Sq(state.sourcePositionResolution);
346 const float varianceR =
347 o2::its::math_utils::Sq(projectionScale) * sourceCoordinateVariance +
348 o2::its::math_utils::Sq(slope * projectionScale) * sourceCoordinateVariance +
349 o2::its::math_utils::Sq(slope * originScale) * vertex.getSigmaZ2() +
350 o2::its::math_utils::Sq(deltaZ * state.edgeMSAngle);
351
352 const auto [evaluatedRadius, evaluatedVariance] = evaluateSearchWindowAt(window, toZ);
353 BOOST_CHECK_EQUAL(evaluatedRadius, expectedRadius);
354 BOOST_CHECK_CLOSE_FRACTION(evaluatedVariance, varianceR, 1.e-6f);
355 BOOST_CHECK_EQUAL(window.phiPrediction, source.phi);
356 BOOST_CHECK_EQUAL(window.phiVariance, o2::its::math_utils::Sq(state.edgePhiCut / params.nSigmaCut));
357
358 TrackletSearchWindow beamUncertaintyWindow{};
359 BOOST_REQUIRE(projectTrackletSearchWindow(sourceMeasurement, vertex, 1.e-3f,
360 SurfaceKind::Disk, state, indexUtils, params.nSigmaCut,
361 beamUncertaintyWindow));
362 const auto [beamRadius, beamVariance] = evaluateSearchWindowAt(beamUncertaintyWindow, toZ);
363 BOOST_CHECK_EQUAL(beamRadius, expectedRadius);
364 BOOST_CHECK_CLOSE_FRACTION(beamVariance,
365 varianceR + o2::its::math_utils::Sq(originScale) * 1.e-3f, 1.e-6f);
366 BOOST_CHECK_EQUAL(beamUncertaintyWindow.phiVariance, window.phiVariance);
367}
368
369BOOST_AUTO_TEST_CASE(DiskProjectSearchWindowUsesCandidateZAndBoundsTheFullTargetInterval)
370{
372 const auto params = makeKernelParameters(legacy, SurfaceKind::Disk);
373 BOOST_REQUIRE(params.isValid());
374
375 IndexTableUtilsCore indexUtils;
376 setDiskLookup(indexUtils, legacy);
377
378 constexpr int fromLayer = 0;
379 constexpr int toLayer = 1;
380 const float fromZ = kMFTSurfaces[fromLayer].referenceCoordinate;
381 const float toZ = kMFTSurfaces[toLayer].referenceCoordinate;
382 const auto source = makeGlobalCluster(1.2f, 0.7f, fromZ);
383 const auto measurement = makeMeasurement(source, 2.e-4f, 3.e-4f);
384 const auto vertex = makeVertex(0.01f, -0.02f, 0.1f, 4.e-4f, 5.e-4f, 0.04f, 3);
385
386 const auto pointTarget = makeDiskProjectionCache(fromLayer, toLayer, 2.f, fromZ, toZ, toZ, 3.e-3f, 0.04f);
387 const auto intervalTarget = makeDiskProjectionCache(fromLayer, toLayer, 2.f, fromZ, toZ - 0.5f, toZ + 0.5f, 3.e-3f, 0.04f);
388 TrackletSearchWindow pointWindow{};
389 TrackletSearchWindow intervalWindow{};
390 BOOST_REQUIRE((projectDiskSearchWindow(measurement, source, vertex, pointTarget, indexUtils, params, pointWindow)));
391 BOOST_REQUIRE((projectDiskSearchWindow(measurement, source, vertex, intervalTarget, indexUtils, params, intervalWindow)));
392
393 const float slope = source.radius / (source.z - vertex.getZ());
394 const float sourceCoordinateVariance = o2::its::math_utils::Sq(intervalTarget.sourcePositionResolution);
395 const float sourceVarianceScale = (1.f + o2::its::math_utils::Sq(slope)) * sourceCoordinateVariance;
396 const float originVarianceScale = o2::its::math_utils::Sq(slope) * vertex.getSigmaZ2();
397 const float edgeMSVarianceScale = o2::its::math_utils::Sq(intervalTarget.edgeMSAngle);
398 const auto predictionAndVarianceAt = [&](float z) {
399 const float deltaZ = z - source.z;
400 const float originScale = deltaZ / (source.z - vertex.getZ());
401 const float projectionScale = 1.f + originScale;
402 const float candidateVariance =
403 o2::its::math_utils::Sq(projectionScale) * sourceVarianceScale +
404 o2::its::math_utils::Sq(originScale) * originVarianceScale +
405 o2::its::math_utils::Sq(deltaZ) * edgeMSVarianceScale;
406 return std::pair{source.radius + slope * deltaZ, candidateVariance};
407 };
408 const auto [minPrediction, minVariance] = predictionAndVarianceAt(intervalTarget.targetMinZ);
409 const auto [maxPrediction, maxVariance] = predictionAndVarianceAt(intervalTarget.targetMaxZ);
410 const float lowerBound = std::min(minPrediction - params.nSigmaCut * std::sqrt(minVariance),
411 maxPrediction - params.nSigmaCut * std::sqrt(maxVariance));
412 const float upperBound = std::max(minPrediction + params.nSigmaCut * std::sqrt(minVariance),
413 maxPrediction + params.nSigmaCut * std::sqrt(maxVariance));
414 const auto directBins = getBinsPhiColumn(source.phi, intervalTarget.toLayer, 0.5f * (lowerBound + upperBound),
415 0.5f * (upperBound - lowerBound), intervalTarget.edgePhiCut, indexUtils);
416
417 BOOST_CHECK_EQUAL(intervalWindow.bins.x, directBins.x);
418 BOOST_CHECK_EQUAL(intervalWindow.bins.y, directBins.y);
419 BOOST_CHECK_EQUAL(intervalWindow.bins.z, directBins.z);
420 BOOST_CHECK_EQUAL(intervalWindow.bins.w, directBins.w);
421 const auto [pointPrediction, pointVariance] = evaluateSearchWindowAt(pointWindow, toZ);
422 const auto [intervalPrediction, intervalVariance] = evaluateSearchWindowAt(intervalWindow, toZ);
423 BOOST_CHECK_CLOSE_FRACTION(intervalPrediction, pointPrediction, 1.e-6f);
424 BOOST_CHECK_CLOSE_FRACTION(intervalVariance, pointVariance, 1.e-6f);
425 BOOST_CHECK_CLOSE_FRACTION(intervalWindow.phiPrediction, pointWindow.phiPrediction, 1.e-6f);
426 BOOST_CHECK_SMALL(intervalWindow.phiVariance - pointWindow.phiVariance, 1.e-9f);
427
428 const auto [evaluatedMinPrediction, evaluatedMinVariance] = evaluateSearchWindowAt(intervalWindow, intervalTarget.targetMinZ);
429 BOOST_CHECK_EQUAL(evaluatedMinPrediction, minPrediction);
430 BOOST_CHECK_CLOSE_FRACTION(evaluatedMinVariance, minVariance, 1.e-6f);
431 const auto [evaluatedMaxPrediction, evaluatedMaxVariance] = evaluateSearchWindowAt(intervalWindow, intervalTarget.targetMaxZ);
432 BOOST_CHECK_EQUAL(evaluatedMaxPrediction, maxPrediction);
433 BOOST_CHECK_CLOSE_FRACTION(evaluatedMaxVariance, maxVariance, 1.e-6f);
434}
435
436BOOST_AUTO_TEST_CASE(ProjectSearchWindowInvalidBinsLeaveEveryOutputFieldUnchanged)
437{
439
440 IndexTableUtilsCore cylinderIndexUtils;
441 configureCylinderIndex(cylinderIndexUtils, legacy);
442 const auto cylinderParams = makeKernelParameters(legacy, SurfaceKind::Cylinder);
443 const auto cylinderSource = makeGlobalCluster(2.f, 0.f, 100.f);
444 const auto cylinderMeasurement = makeMeasurement(cylinderSource);
445 const auto cylinderVertex = makeVertex(0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
446 const auto cylinderState = makeCylinderProjectionCache(0, 3, 2.f, 4.f, 3.8f, 4.2f, 5.e-4f, 2.e-3f, 0.08f);
447 const TrackletSearchWindow cylinderSentinel{
448 {101, 102, 103, 104}, 105.f, 106.f, 107.f, 108.f, 109.f, 110.f, 111.f, 112.f};
449 auto cylinderOut = cylinderSentinel;
450 BOOST_CHECK(!(projectCylinderSearchWindow(
451 cylinderMeasurement, cylinderSource, cylinderVertex, cylinderState, cylinderIndexUtils, cylinderParams, cylinderOut)));
452 checkSearchWindowEqual(cylinderOut, cylinderSentinel);
453
454 IndexTableUtilsCore diskIndexUtils;
455 setDiskLookup(diskIndexUtils, legacy, 0.1f, 0.01f);
456 const auto diskParams = makeKernelParameters(legacy, SurfaceKind::Disk);
457 constexpr int fromLayer = 0;
458 constexpr int toLayer = 1;
459 const float fromZ = kMFTSurfaces[fromLayer].referenceCoordinate;
460 const float toZ = kMFTSurfaces[toLayer].referenceCoordinate;
461 const auto diskSource = makeGlobalCluster(1.f, 0.5f, fromZ);
462 const auto diskMeasurement = makeMeasurement(diskSource);
463 const auto diskVertex = makeVertex(0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
464 const auto diskState = makeDiskProjectionCache(fromLayer, toLayer, 2.f, fromZ, toZ, toZ, 3.e-3f, 0.04f);
465 const TrackletSearchWindow diskSentinel{
466 {201, 202, 203, 204}, 205.f, 206.f, 207.f, 208.f, 209.f, 210.f, 211.f, 212.f};
467 auto diskOut = diskSentinel;
468 BOOST_CHECK(!(projectDiskSearchWindow(
469 diskMeasurement, diskSource, diskVertex, diskState, diskIndexUtils, diskParams, diskOut)));
470 checkSearchWindowEqual(diskOut, diskSentinel);
471}
472
473BOOST_AUTO_TEST_CASE(DiskProjectionUsesBeamCenteredPolarCoordinatesAndIgnoresVertexXY)
474{
476 const auto params = makeKernelParameters(legacy, SurfaceKind::Disk);
477 constexpr int fromLayer = 0;
478 constexpr int toLayer = 1;
479 const float fromZ = kMFTSurfaces[fromLayer].referenceCoordinate;
480 const float toZ = kMFTSurfaces[toLayer].referenceCoordinate;
481 const auto source = makeGlobalCluster(1.f, 0.5f, fromZ);
482 const auto sourceMeasurement = makeMeasurement(source);
483 const auto state = makeDiskProjectionCache(fromLayer, toLayer, 2.f, fromZ, toZ, toZ, 3.e-3f, 0.04f);
484
485 IndexTableUtilsCore indexUtils;
486 setDiskLookup(indexUtils, legacy);
487
488 const auto straightVertex = makeVertex(0.1f, -0.2f, 0.3f, 4.e-4f, 5.e-4f, 0.04f);
489 TrackletSearchWindow straightWindow{};
490 BOOST_REQUIRE((projectDiskSearchWindow(
491 sourceMeasurement, source, straightVertex, state, indexUtils, params, straightWindow)));
492 const float slope = source.radius / (source.z - straightVertex.getZ());
493 const float expectedRadius = source.radius + slope * (toZ - source.z);
494 const auto [straightPrediction, straightVariance] = evaluateSearchWindowAt(straightWindow, toZ);
495 BOOST_CHECK_EQUAL(straightPrediction, expectedRadius);
496 BOOST_CHECK(straightVariance > 0.f);
497 BOOST_CHECK_EQUAL(straightWindow.phiPrediction, source.phi);
498
499 const auto displacedVertex = makeVertex(-3.f, 4.f, straightVertex.getZ(), 8.f, 9.f, straightVertex.getSigmaZ2());
500 TrackletSearchWindow displacedWindow{};
501 BOOST_REQUIRE((projectDiskSearchWindow(
502 sourceMeasurement, source, displacedVertex, state, indexUtils, params, displacedWindow)));
503 checkSearchWindowEqual(displacedWindow, straightWindow);
504
505 const auto fallbackVertex = makeVertex(0.1f, -0.2f, fromZ, 4.e-4f, 5.e-4f, 0.f);
506 TrackletSearchWindow fallbackWindow{};
507 const TrackletSearchWindow sentinel{{1, 2, 3, 4}, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f, 12.f};
508 fallbackWindow = sentinel;
509 BOOST_CHECK(!(projectDiskSearchWindow(
510 sourceMeasurement, source, fallbackVertex, state, indexUtils, params, fallbackWindow)));
511 checkSearchWindowEqual(fallbackWindow, sentinel);
512}
513
514BOOST_AUTO_TEST_CASE(GlobalMeasurementsAreTheSoleCoordinateAuthority)
515{
516 ReferenceTrackingParameters cylinderParameters;
517 cylinderParameters.PVres = 0.f;
518 const auto cylinderKernelParameters = makeKernelParameters(cylinderParameters, SurfaceKind::Cylinder);
519 IndexTableUtilsCore cylinderIndex;
520 configureCylinderIndex(cylinderIndex, cylinderParameters);
521 const auto vertex = makeVertex(0.f, 0.f, 0.f, 1.e-4f, 1.e-4f, 4.e-4f, 4);
522 const auto cylinderState = makeCylinderProjectionCache(0, 1, 2.f, 4.f, 3.8f, 4.2f, 5.e-4f, 2.e-3f, 0.08f);
523 const auto sourceMeasurement = makeMeasurement(2.f, 0.f, 0.5f);
524 const auto source = makeGlobalCluster(2.f, 0.f, 0.5f);
525
526 TrackletSearchWindow baseline{};
527 BOOST_REQUIRE((projectCylinderSearchWindow(
528 sourceMeasurement, source, vertex, cylinderState, cylinderIndex, cylinderKernelParameters, baseline)));
529
530 auto poisonedSource = source;
531 poisonedSource.x = -999.f;
532 poisonedSource.y = 888.f;
533 poisonedSource.z = -777.f;
534 TrackletSearchWindow poisonedWindow{};
535 BOOST_REQUIRE((projectCylinderSearchWindow(
536 sourceMeasurement, poisonedSource, vertex, cylinderState, cylinderIndex, cylinderKernelParameters, poisonedWindow)));
537 checkSearchWindowEqual(poisonedWindow, baseline);
538
539 auto poisonedNavigationCache = source;
540 poisonedNavigationCache.radius = 4.f;
541 TrackletSearchWindow cachePoisonedWindow{};
542 BOOST_REQUIRE((projectCylinderSearchWindow(
543 sourceMeasurement, poisonedNavigationCache, vertex, cylinderState, cylinderIndex, cylinderKernelParameters, cachePoisonedWindow)));
544 checkSearchWindowEqual(cachePoisonedWindow, baseline);
545
546 ReferenceTrackingParameters diskParameters;
547 const auto diskKernelParameters = makeKernelParameters(diskParameters, SurfaceKind::Disk);
548 IndexTableUtilsCore diskIndex;
549 setDiskLookup(diskIndex, diskParameters);
550 const float fromZ = kMFTSurfaces[0].referenceCoordinate;
551 const float toZ = kMFTSurfaces[1].referenceCoordinate;
552 const auto diskMeasurement = makeMeasurement(1.f, 0.5f, fromZ, 2.e-4f, 3.e-4f, 7.f);
553 auto diskLocator = makeGlobalCluster(1.f, 0.5f, fromZ);
554 const auto diskState = makeDiskProjectionCache(0, 1, 2.f, fromZ, toZ, toZ, 3.e-3f, 0.04f);
555 TrackletSearchWindow diskBaseline{};
556 BOOST_REQUIRE((projectDiskSearchWindow(
557 diskMeasurement, diskLocator, vertex, diskState, diskIndex, diskKernelParameters, diskBaseline)));
558 diskLocator.x = 123.f;
559 diskLocator.y = -321.f;
560 diskLocator.z = 456.f;
561 auto uvPoisoned = diskMeasurement;
562 uvPoisoned.covariance.xy = -12345.f;
563 TrackletSearchWindow diskPoisoned{};
564 BOOST_REQUIRE((projectDiskSearchWindow(
565 uvPoisoned, diskLocator, vertex, diskState, diskIndex, diskKernelParameters, diskPoisoned)));
566 checkSearchWindowEqual(diskPoisoned, diskBaseline);
567}
header::DataOrigin origin
uint64_t vertex
Definition RawEventData.h:9
SurfaceTrackState state
bounded_vector< int > contributors
Definition of the MagF class.
uint16_t slope
Definition RawData.h:1
Shared host/device helpers for ITS tracker trait implementations.
static MagneticField * createNominalField(int fld, bool uniform=false)
create field from rounded value, i.e. +-5 or +-2 kGauss
void setIndexTableParams(IndexTableCoordType coordType, int nRowBins, int nColBins, float rowMin, float rowMax, gsl::span< const float > layerColMin, gsl::span< const float > layerColMax)
GLfloat GLfloat GLfloat alpha
Definition glcorearb.h:279
GLint GLenum GLint x
Definition glcorearb.h:403
GLuint index
Definition glcorearb.h:781
GLsizei GLsizei GLchar * source
Definition glcorearb.h:798
GLint y
Definition glcorearb.h:270
GLenum const GLfloat * params
Definition glcorearb.h:272
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLenum GLuint GLint GLint layer
Definition glcorearb.h:1310
GLuint id
Definition glcorearb.h:650
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
constexpr std::array< SurfaceDescriptor, MFTNLayers > kMFTSurfaces
constexpr std::array< SurfaceDescriptor, ITSNLayers > kITSSurfaces
bool configureIndexTableUtils(o2::itsmft::IndexTableUtilsCore &destination, const DetectorParameters &params, int activeSurfaceCount, SurfaceKind kind, gsl::span< const SurfaceChartRange > chartRanges) noexcept
constexpr int ITSNLayers
ITS CA layer count.
bool projectTrackletSearchWindow(const GlobalMeasurement &sourceMeasurement, const o2::its::Vertex &vertex, float beamPositionVariance, SurfaceKind kind, const TrackletProjectionCache &edgeCache, const o2::itsmft::IndexTableUtilsCore &indexUtils, float nSigmaCut, TrackletSearchWindow &out)
BOOST_AUTO_TEST_CASE(Cluster_messageable)
D const SVectorGPU< T, D > & rhs
Definition SMatrixGPU.h:193
float TrackletMinPt
Trackleting cuts.
float MaxChi2ClusterAttachment
Fitter parameters.
BOOST_GLOBAL_FIXTURE(PropagatorFieldFixture)
BOOST_CHECK(tree)
BOOST_CHECK_EQUAL(triggersD.size(), triggers.size())