From 493a1beb782559486cfc28377f53b997eec1aeff Mon Sep 17 00:00:00 2001 From: Benjamin Huth Date: Fri, 20 Mar 2026 20:26:48 +0100 Subject: [PATCH 1/8] add test script --- .github/workflows/builds.yml | 2 +- .../Python/track_finding_python_only.py | 166 ++++++++++++++++++ Python/Core/src/EventData.cpp | 9 +- Python/Examples/scripts/hello_world_kalman.py | 129 -------------- Python/Examples/src/EventData.cpp | 62 +++++++ 5 files changed, 237 insertions(+), 131 deletions(-) create mode 100644 Examples/Scripts/Python/track_finding_python_only.py delete mode 100755 Python/Examples/scripts/hello_world_kalman.py diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index f5633dd72e1..d5a64a9a9e9 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -635,4 +635,4 @@ jobs: path: "*.whl" - name: Test - run: CI/dependencies/run.sh .env python3 Python/Examples/scripts/hello_world_kalman.py + run: CI/dependencies/run.sh .env python3 Examples/Scripts/Python/track_finding_python_only.py diff --git a/Examples/Scripts/Python/track_finding_python_only.py b/Examples/Scripts/Python/track_finding_python_only.py new file mode 100644 index 00000000000..43261c7ef3c --- /dev/null +++ b/Examples/Scripts/Python/track_finding_python_only.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python3 +# This file is part of the ACTS project. +# +# Copyright (C) 2016 CERN for the benefit of the ACTS project +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. + +import os +from pathlib import Path + +os.environ["ACTS_SEQUENCER_DISABLE_FPEMON"] = "1" + +import acts +import acts.examples +from acts import UnitConstants as u + + +def runTrackFindingPythonOnly( + trackingGeometry, + field, + digiConfigFile, + geoSelectionConfigFile, + outputDir, + decorators=[], + s=None, +): + from acts.examples.simulation import ( + addParticleGun, + MomentumConfig, + EtaConfig, + PhiConfig, + ParticleConfig, + addFatras, + addDigitization, + ) + + s = s or acts.examples.Sequencer(events=1, numThreads=1, logLevel=acts.logging.INFO) + outputDir = Path(outputDir) + rnd = acts.examples.RandomNumbers(seed=42) + + for d in decorators: + s.addContextDecorator(d) + + addParticleGun( + s, + MomentumConfig(1.0 * u.GeV, 10.0 * u.GeV, transverse=True), + EtaConfig(-2.0, 2.0, uniform=True), + PhiConfig(0.0, 360.0 * u.degree), + ParticleConfig(1, acts.PdgParticle.eMuon, randomizeCharge=True), + rnd=rnd, + ) + + addFatras( + s, + trackingGeometry, + field, + rnd=rnd, + ) + + addDigitization( + s, + trackingGeometry, + field, + digiConfigFile=digiConfigFile, + rnd=rnd, + ) + + s.addAlgorithm( + acts.examples.SpacePointMaker( + level=acts.logging.INFO, + trackingGeometry=trackingGeometry, + inputMeasurements="measurements", + outputSpacePoints="spacepoints", + geometrySelection=acts.examples.json.readJsonGeometryList( + str(geoSelectionConfigFile) + ), + ) + ) + + class PythonTrackFinder(acts.examples.IAlgorithm): + def __init__(self, name, level): + acts.examples.IAlgorithm.__init__(self, name, level) + + self.spacepoints = acts.examples.ReadDataHandle( + self, acts.SpacePointContainer2, "Spacepoints" + ) + self.spacepoints.initialize("spacepoints") + + self.prototracks = acts.examples.WriteDataHandle( + self, acts.examples.ProtoTrackContainer, "Prototracks" + ) + self.prototracks.initialize("prototracks") + + def execute(self, context): + spacepoints = self.spacepoints(context.eventStore) + + track = acts.examples.ProtoTrack() + for sp in sorted(spacepoints, key=lambda sp: sp.r): + for sl in sp.sourceLinks: + isl = acts.examples.IndexSourceLink.FromSourceLink(sl) + track.append(isl.index()) + + prototracks = acts.examples.ProtoTrackContainer() + prototracks.append(track) + + self.prototracks(context, prototracks) + return acts.examples.ProcessCode.SUCCESS + + s.addAlgorithm(PythonTrackFinder("PythonTrackFinder", acts.logging.INFO)) + + class PythonTrackFitter(acts.examples.IAlgorithm): + def __init__(self, name, level): + acts.examples.IAlgorithm.__init__(self, name, level) + + self.prototracks = acts.examples.ReadDataHandle( + self, acts.examples.ProtoTrackContainer, "Prototracks" + ) + self.prototracks.initialize("prototracks") + + self.tracks = acts.examples.WriteDataHandle( + self, acts.examples.ConstTrackContainer, "Tracks" + ) + self.tracks.initialize("fitted_tracks") + + def execute(self, context): + prototracks = self.prototracks(context.eventStore) + + container = acts.examples.MutableTrackContainer() + for prototrack in prototracks: + track = container.makeTrack() + track.setParameters([1.0, 1.0, 1.0, 1.0, 1.0, 1.0]) + track.nMeasurements = len(prototrack) + + self.tracks(context, container.makeConst()) + return acts.examples.ProcessCode.SUCCESS + + s.addAlgorithm(PythonTrackFitter("PythonTrackFitter", acts.logging.INFO)) + + return s + + +if __name__ == "__main__": + srcdir = Path(__file__).resolve().parent.parent.parent.parent + + detector = acts.examples.GenericDetector(acts.examples.GenericDetector.Config()) + trackingGeometry = detector.trackingGeometry() + decorators = detector.contextDecorators() + + field = acts.ConstantBField(acts.Vector3(0.0, 0.0, 2.0 * u.T)) + + digiConfigFile = srcdir / "Examples/Configs/generic-digi-smearing-config.json" + geoSelectionConfigFile = srcdir / "Examples/Configs/generic-seeding-config.json" + + outputDir = Path.cwd() / "output_track_finding_python_only" + outputDir.mkdir(exist_ok=True) + + runTrackFindingPythonOnly( + trackingGeometry=trackingGeometry, + field=field, + digiConfigFile=digiConfigFile, + geoSelectionConfigFile=geoSelectionConfigFile, + outputDir=outputDir, + decorators=decorators, + ).run() diff --git a/Python/Core/src/EventData.cpp b/Python/Core/src/EventData.cpp index 18d94267249..dc873ca35ea 100644 --- a/Python/Core/src/EventData.cpp +++ b/Python/Core/src/EventData.cpp @@ -222,7 +222,14 @@ void addEventData(py::module_& m) { static_cast(&ConstSpacePointProxy2::varianceZ)) .def_property_readonly( "varianceR", - static_cast(&ConstSpacePointProxy2::varianceR)); + static_cast(&ConstSpacePointProxy2::varianceR)) + .def_property_readonly( + "sourceLinks", py::cpp_function( + [](const ConstSpacePointProxy2& self) { + auto sls = self.sourceLinks(); + return py::make_iterator(sls.begin(), sls.end()); + }, + py::keep_alive<0, 1>())); // SeedContainer2 auto seedContainer2 = diff --git a/Python/Examples/scripts/hello_world_kalman.py b/Python/Examples/scripts/hello_world_kalman.py deleted file mode 100755 index d08a67abb0b..00000000000 --- a/Python/Examples/scripts/hello_world_kalman.py +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/env python3 - -from pathlib import Path -import json - -import acts -import acts.examples - -from acts.examples.simulation import ( - addParticleGun, - ParticleConfig, - EtaConfig, - PhiConfig, - MomentumConfig, - addFatras, - addDigitization, - ParticleSelectorConfig, - addDigiParticleSelection, -) - -from acts.examples.reconstruction import ( - addSeeding, - SeedingAlgorithm, - addKalmanTracks, - addTrackWriters, -) - -u = acts.UnitConstants - - -if "__main__" == __name__: - # GenericDetector - detector = acts.examples.GenericDetector() - trackingGeometry = detector.trackingGeometry() - - # Create minimal digitization config with only volume id 0 (broadcasts to all surfaces) - digiConfig = { - "acts-geometry-hierarchy-map": { - "format-version": 0, - "value-identifier": "digitization-configuration", - }, - "entries": [ - { - "volume": 0, - "value": { - "smearing": [ - {"index": 0, "mean": 0.0, "stddev": 0.01, "type": "Gauss"}, - {"index": 1, "mean": 0.0, "stddev": 0.01, "type": "Gauss"}, - ] - }, - } - ], - } - - # Save config to file - digiConfigFile = Path.cwd() / "digi-config-minimal.json" - with open(digiConfigFile, "w") as f: - json.dump(digiConfig, f, indent=4) - logger = acts.getDefaultLogger("Truth tracking example", acts.logging.INFO) - logger.info(f"Saved minimal digitization config to {digiConfigFile}") - - field = acts.ConstantBField(acts.Vector3(0, 0, 2 * u.T)) - - s = acts.examples.Sequencer(events=10, numThreads=-1, logLevel=acts.logging.INFO) - - rnd = acts.examples.RandomNumbers(seed=42) - - addParticleGun( - s, - ParticleConfig(num=1, pdg=acts.PdgParticle.eMuon, randomizeCharge=True), - EtaConfig(-3.0, 3.0, uniform=True), - MomentumConfig(1.0 * u.GeV, 100.0 * u.GeV, transverse=True), - PhiConfig(0.0, 360.0 * u.degree), - vtxGen=acts.examples.GaussianVertexGenerator( - mean=acts.Vector4(0, 0, 0, 0), - stddev=acts.Vector4(0, 0, 0, 0), - ), - multiplicity=1, - rnd=rnd, - ) - - addFatras( - s, - trackingGeometry, - field, - rnd=rnd, - enableInteractions=True, - ) - - addDigitization( - s, - trackingGeometry, - field, - digiConfigFile=digiConfigFile, - rnd=rnd, - ) - - addDigiParticleSelection( - s, - ParticleSelectorConfig( - pt=(0.9 * u.GeV, None), - measurements=(7, None), - removeNeutral=True, - removeSecondaries=True, - ), - ) - - addSeeding( - s, - trackingGeometry, - field, - rnd=rnd, - inputParticles="particles_generated", - seedingAlgorithm=SeedingAlgorithm.TruthSmeared, - ) - - addKalmanTracks( - s, - trackingGeometry, - field, - ) - - addTrackWriters( - s, - name="tracks", - outputDirCsv="csv", - ) - - s.run() diff --git a/Python/Examples/src/EventData.cpp b/Python/Examples/src/EventData.cpp index 83932226d3f..9f5c92c3a27 100644 --- a/Python/Examples/src/EventData.cpp +++ b/Python/Examples/src/EventData.cpp @@ -7,6 +7,7 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. #include "Acts/EventData/SpacePointContainer2.hpp" +#include "ActsExamples/EventData/IndexSourceLink.hpp" #include "ActsExamples/EventData/ProtoTrack.hpp" #include "ActsExamples/EventData/Track.hpp" #include "ActsPython/Utilities/WhiteBoardRegistry.hpp" @@ -244,6 +245,67 @@ void addEventData(py::module& mex) { WhiteBoardRegistry::registerClass(protoTrackContainer); mex.attr("kTrackIndexInvalid") = Acts::kTrackIndexInvalid; + + py::class_(mex, "IndexSourceLink") + .def("FromSourceLink", + [](Acts::SourceLink const& sl) { return sl.get(); }) + .def("index", &IndexSourceLink::index) + .def("geometryId", &IndexSourceLink::geometryId); + + py::class_(mex, "MutableTrackProxy") + .def("setReferenceSurface", + [](TrackProxy& self, std::shared_ptr srf) { + self.setReferenceSurface(std::move(srf)); + }) + .def("setParameters", + [](TrackProxy& self, const Acts::BoundVector& params) { + self.parameters() = params; + }) + .def("setCovariance", + [](TrackProxy& self, const Acts::BoundMatrix& cov) { + self.covariance() = cov; + }) + .def("setParticleHypothesis", + [](TrackProxy& self, const Acts::ParticleHypothesis& hyp) { + self.setParticleHypothesis(hyp); + }) + .def_property( + "nMeasurements", + [](TrackProxy& self) -> std::uint32_t { + return self.nMeasurements(); + }, + [](TrackProxy& self, std::uint32_t n) { self.nMeasurements() = n; }) + .def_property( + "nHoles", + [](TrackProxy& self) -> std::uint32_t { return self.nHoles(); }, + [](TrackProxy& self, std::uint32_t n) { self.nHoles() = n; }) + .def_property( + "chi2", [](TrackProxy& self) -> float { return self.chi2(); }, + [](TrackProxy& self, float v) { self.chi2() = v; }); + + struct PyMutableTrackContainer { + std::shared_ptr trackContainer = + std::make_shared(); + std::shared_ptr mtj = + std::make_shared(); + TrackContainer tracks{trackContainer, mtj}; + + TrackProxy makeTrack() { return tracks.makeTrack(); } + std::size_t size() const { return tracks.size(); } + ConstTrackContainer makeConst() { + return ConstTrackContainer{ + std::make_shared( + std::move(*trackContainer)), + std::make_shared(std::move(*mtj))}; + } + }; + + py::class_(mex, "MutableTrackContainer") + .def(py::init<>()) + .def("__len__", &PyMutableTrackContainer::size) + .def("makeTrack", &PyMutableTrackContainer::makeTrack, + py::keep_alive<0, 1>()) + .def("makeConst", &PyMutableTrackContainer::makeConst); } } // namespace ActsPython From 8d58418cb9acb303ed5ede203b5a0d7bf5dbb5f7 Mon Sep 17 00:00:00 2001 From: Benjamin Huth Date: Fri, 20 Mar 2026 21:59:53 +0100 Subject: [PATCH 2/8] update --- .../Python/track_finding_python_only.py | 2 +- Python/Examples/src/EventData.cpp | 40 ++++++++----------- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/Examples/Scripts/Python/track_finding_python_only.py b/Examples/Scripts/Python/track_finding_python_only.py index 43261c7ef3c..8d9f570ee81 100644 --- a/Examples/Scripts/Python/track_finding_python_only.py +++ b/Examples/Scripts/Python/track_finding_python_only.py @@ -127,7 +127,7 @@ def __init__(self, name, level): def execute(self, context): prototracks = self.prototracks(context.eventStore) - container = acts.examples.MutableTrackContainer() + container = acts.examples.TrackContainer() for prototrack in prototracks: track = container.makeTrack() track.setParameters([1.0, 1.0, 1.0, 1.0, 1.0, 1.0]) diff --git a/Python/Examples/src/EventData.cpp b/Python/Examples/src/EventData.cpp index 9f5c92c3a27..670df94cb74 100644 --- a/Python/Examples/src/EventData.cpp +++ b/Python/Examples/src/EventData.cpp @@ -252,7 +252,7 @@ void addEventData(py::module& mex) { .def("index", &IndexSourceLink::index) .def("geometryId", &IndexSourceLink::geometryId); - py::class_(mex, "MutableTrackProxy") + py::class_(mex, "TrackProxy") .def("setReferenceSurface", [](TrackProxy& self, std::shared_ptr srf) { self.setReferenceSurface(std::move(srf)); @@ -283,29 +283,21 @@ void addEventData(py::module& mex) { "chi2", [](TrackProxy& self) -> float { return self.chi2(); }, [](TrackProxy& self, float v) { self.chi2() = v; }); - struct PyMutableTrackContainer { - std::shared_ptr trackContainer = - std::make_shared(); - std::shared_ptr mtj = - std::make_shared(); - TrackContainer tracks{trackContainer, mtj}; - - TrackProxy makeTrack() { return tracks.makeTrack(); } - std::size_t size() const { return tracks.size(); } - ConstTrackContainer makeConst() { - return ConstTrackContainer{ - std::make_shared( - std::move(*trackContainer)), - std::make_shared(std::move(*mtj))}; - } - }; - - py::class_(mex, "MutableTrackContainer") - .def(py::init<>()) - .def("__len__", &PyMutableTrackContainer::size) - .def("makeTrack", &PyMutableTrackContainer::makeTrack, - py::keep_alive<0, 1>()) - .def("makeConst", &PyMutableTrackContainer::makeConst); + py::class_(mex, "TrackContainer") + .def(py::init([]() { + return TrackContainer{ + std::make_shared(), + std::make_shared()}; + })) + .def("__len__", &TrackContainer::size) + .def("makeTrack", &TrackContainer::makeTrack, py::keep_alive<0, 1>()) + .def("makeConst", [](TrackContainer& self) { + return ConstTrackContainer{ + std::make_shared( + std::move(self.container())), + std::make_shared( + std::move(self.trackStateContainer()))}; + }); } } // namespace ActsPython From 75b349d069ab6bdc6a8991cf86448519a995f083 Mon Sep 17 00:00:00 2001 From: Benjamin Huth Date: Fri, 20 Mar 2026 22:08:33 +0100 Subject: [PATCH 3/8] update --- .../Python/track_finding_python_only.py | 2 +- Python/Examples/src/EventData.cpp | 38 ++++++++++++------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/Examples/Scripts/Python/track_finding_python_only.py b/Examples/Scripts/Python/track_finding_python_only.py index 8d9f570ee81..886ea0ed609 100644 --- a/Examples/Scripts/Python/track_finding_python_only.py +++ b/Examples/Scripts/Python/track_finding_python_only.py @@ -130,7 +130,7 @@ def execute(self, context): container = acts.examples.TrackContainer() for prototrack in prototracks: track = container.makeTrack() - track.setParameters([1.0, 1.0, 1.0, 1.0, 1.0, 1.0]) + track.parameters = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] track.nMeasurements = len(prototrack) self.tracks(context, container.makeConst()) diff --git a/Python/Examples/src/EventData.cpp b/Python/Examples/src/EventData.cpp index 670df94cb74..a4272d76c24 100644 --- a/Python/Examples/src/EventData.cpp +++ b/Python/Examples/src/EventData.cpp @@ -253,41 +253,51 @@ void addEventData(py::module& mex) { .def("geometryId", &IndexSourceLink::geometryId); py::class_(mex, "TrackProxy") + .def_property_readonly("referenceSurface", &TrackProxy::referenceSurface) .def("setReferenceSurface", [](TrackProxy& self, std::shared_ptr srf) { self.setReferenceSurface(std::move(srf)); }) - .def("setParameters", - [](TrackProxy& self, const Acts::BoundVector& params) { - self.parameters() = params; - }) - .def("setCovariance", - [](TrackProxy& self, const Acts::BoundMatrix& cov) { - self.covariance() = cov; - }) + .def_property( + "parameters", + [](const TrackProxy& self) { + return Acts::BoundVector{self.parameters()}; + }, + [](TrackProxy& self, const Acts::BoundVector& v) { + self.parameters() = v; + }) + .def_property( + "covariance", + [](const TrackProxy& self) { + return Acts::BoundMatrix{self.covariance()}; + }, + [](TrackProxy& self, const Acts::BoundMatrix& m) { + self.covariance() = m; + }) + .def_property_readonly("particleHypothesis", + &TrackProxy::particleHypothesis) .def("setParticleHypothesis", [](TrackProxy& self, const Acts::ParticleHypothesis& hyp) { self.setParticleHypothesis(hyp); }) .def_property( "nMeasurements", - [](TrackProxy& self) -> std::uint32_t { + [](const TrackProxy& self) -> std::uint32_t { return self.nMeasurements(); }, [](TrackProxy& self, std::uint32_t n) { self.nMeasurements() = n; }) .def_property( "nHoles", - [](TrackProxy& self) -> std::uint32_t { return self.nHoles(); }, + [](const TrackProxy& self) -> std::uint32_t { return self.nHoles(); }, [](TrackProxy& self, std::uint32_t n) { self.nHoles() = n; }) .def_property( - "chi2", [](TrackProxy& self) -> float { return self.chi2(); }, + "chi2", [](const TrackProxy& self) -> float { return self.chi2(); }, [](TrackProxy& self, float v) { self.chi2() = v; }); py::class_(mex, "TrackContainer") .def(py::init([]() { - return TrackContainer{ - std::make_shared(), - std::make_shared()}; + return TrackContainer{std::make_shared(), + std::make_shared()}; })) .def("__len__", &TrackContainer::size) .def("makeTrack", &TrackContainer::makeTrack, py::keep_alive<0, 1>()) From eece02a2573f8b01d9e7b306795341e53b1c12c2 Mon Sep 17 00:00:00 2001 From: Benjamin Huth <37871400+benjaminhuth@users.noreply.github.com> Date: Sun, 22 Mar 2026 13:42:08 +0100 Subject: [PATCH 4/8] Update track parameters to use BoundVector --- Examples/Scripts/Python/track_finding_python_only.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Examples/Scripts/Python/track_finding_python_only.py b/Examples/Scripts/Python/track_finding_python_only.py index 886ea0ed609..79c7805b65d 100644 --- a/Examples/Scripts/Python/track_finding_python_only.py +++ b/Examples/Scripts/Python/track_finding_python_only.py @@ -130,7 +130,7 @@ def execute(self, context): container = acts.examples.TrackContainer() for prototrack in prototracks: track = container.makeTrack() - track.parameters = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + track.parameters = acts.BoundVector(1.0, 1.0, 1.0, 1.0, 1.0, 1.0) track.nMeasurements = len(prototrack) self.tracks(context, container.makeConst()) From 8eeb1a3ca777b3fe3cf0b9cf21135a59d53f6074 Mon Sep 17 00:00:00 2001 From: Benjamin Huth Date: Sun, 22 Mar 2026 17:18:08 +0100 Subject: [PATCH 5/8] remove pybind11/eigen.h header, since it introduces bindings for BoundVector based on numpy, which we don't want --- Python/Examples/src/EventData.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Python/Examples/src/EventData.cpp b/Python/Examples/src/EventData.cpp index a4272d76c24..dbb0dde8723 100644 --- a/Python/Examples/src/EventData.cpp +++ b/Python/Examples/src/EventData.cpp @@ -12,7 +12,6 @@ #include "ActsExamples/EventData/Track.hpp" #include "ActsPython/Utilities/WhiteBoardRegistry.hpp" -#include #include #include #include From b3dca181937a5919205c6a51eb96981524723768 Mon Sep 17 00:00:00 2001 From: Benjamin Huth Date: Sun, 22 Mar 2026 23:58:40 +0100 Subject: [PATCH 6/8] update --- Python/Examples/tests/test_truth_tracking.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Python/Examples/tests/test_truth_tracking.py b/Python/Examples/tests/test_truth_tracking.py index a4f15410ce9..567babe02da 100644 --- a/Python/Examples/tests/test_truth_tracking.py +++ b/Python/Examples/tests/test_truth_tracking.py @@ -232,12 +232,15 @@ def execute(self, context): for track in tracks: params = track.parameters - assert params.shape == (6,) + assert isinstance(params, acts.BoundVector) cov = track.covariance - assert cov.shape == (6, 6) + assert isinstance(cov, acts.BoundMatrix) # parameters from per-proxy accessor must match the # bulk numpy array at the same index - assert np.allclose(params, tracks.parameters[track.index]) + assert np.allclose( + [params[i] for i in range(6)], + tracks.parameters[track.index], + ) n_meas_from_summary = track.nMeasurements n_meas_counted = 0 @@ -263,15 +266,15 @@ def execute(self, context): if state.hasPredicted: pred = state.predicted - assert pred.shape == (6,) + assert isinstance(pred, acts.BoundVector) if state.hasFiltered: filt = state.filtered - assert filt.shape == (6,) + assert isinstance(filt, acts.BoundVector) if state.hasSmoothed: smth = state.smoothed - assert smth.shape == (6,) + assert isinstance(smth, acts.BoundVector) assert n_meas_counted == n_meas_from_summary assert n_holes_counted == track.nHoles @@ -290,7 +293,9 @@ def execute(self, context): ] assert len(fwd_predicted) == len(rev_predicted) for fwd, rev in zip(fwd_predicted, reversed(rev_predicted)): - assert np.allclose(fwd, rev) + assert all( + fwd[i] == pytest.approx(rev[i]) for i in range(6) + ) return acts.examples.ProcessCode.SUCCESS From 4aa9acc636b39b8acd1291878ac15c15f0d310fa Mon Sep 17 00:00:00 2001 From: Benjamin Huth Date: Mon, 23 Mar 2026 11:18:35 +0100 Subject: [PATCH 7/8] lint --- Python/Examples/tests/test_truth_tracking.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Python/Examples/tests/test_truth_tracking.py b/Python/Examples/tests/test_truth_tracking.py index 567babe02da..c6058f75cf9 100644 --- a/Python/Examples/tests/test_truth_tracking.py +++ b/Python/Examples/tests/test_truth_tracking.py @@ -293,9 +293,7 @@ def execute(self, context): ] assert len(fwd_predicted) == len(rev_predicted) for fwd, rev in zip(fwd_predicted, reversed(rev_predicted)): - assert all( - fwd[i] == pytest.approx(rev[i]) for i in range(6) - ) + assert all(fwd[i] == pytest.approx(rev[i]) for i in range(6)) return acts.examples.ProcessCode.SUCCESS From 8a6d8e731901335bc2007c10fc1ef71c3fe80a7c Mon Sep 17 00:00:00 2001 From: Benjamin Huth Date: Mon, 23 Mar 2026 17:08:33 +0100 Subject: [PATCH 8/8] update --- Python/Examples/src/EventData.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Python/Examples/src/EventData.cpp b/Python/Examples/src/EventData.cpp index dbb0dde8723..ca60348d71e 100644 --- a/Python/Examples/src/EventData.cpp +++ b/Python/Examples/src/EventData.cpp @@ -252,11 +252,14 @@ void addEventData(py::module& mex) { .def("geometryId", &IndexSourceLink::geometryId); py::class_(mex, "TrackProxy") - .def_property_readonly("referenceSurface", &TrackProxy::referenceSurface) - .def("setReferenceSurface", - [](TrackProxy& self, std::shared_ptr srf) { - self.setReferenceSurface(std::move(srf)); - }) + .def_property( + "referenceSurface", + [](const TrackProxy& self) -> const Acts::Surface& { + return self.referenceSurface(); + }, + [](TrackProxy& self, std::shared_ptr srf) { + self.setReferenceSurface(std::move(srf)); + }) .def_property( "parameters", [](const TrackProxy& self) { @@ -273,12 +276,12 @@ void addEventData(py::module& mex) { [](TrackProxy& self, const Acts::BoundMatrix& m) { self.covariance() = m; }) - .def_property_readonly("particleHypothesis", - &TrackProxy::particleHypothesis) - .def("setParticleHypothesis", - [](TrackProxy& self, const Acts::ParticleHypothesis& hyp) { - self.setParticleHypothesis(hyp); - }) + .def_property( + "particleHypothesis", + [](const TrackProxy& self) { return self.particleHypothesis(); }, + [](TrackProxy& self, const Acts::ParticleHypothesis& hyp) { + self.setParticleHypothesis(hyp); + }) .def_property( "nMeasurements", [](const TrackProxy& self) -> std::uint32_t {