diff --git a/Core/include/Acts/EventData/SubspaceHelpers.hpp b/Core/include/Acts/EventData/SubspaceHelpers.hpp index 8a27e7d7208..49a59e1dae7 100644 --- a/Core/include/Acts/EventData/SubspaceHelpers.hpp +++ b/Core/include/Acts/EventData/SubspaceHelpers.hpp @@ -39,7 +39,7 @@ inline static bool checkSubspaceIndices(const Container& container, if (subspaceSize > fullSize) { return false; } - if (container.size() != subspaceSize) { + if (static_cast(container.size()) != subspaceSize) { return false; } for (auto it = container.begin(); it != container.end();) { @@ -115,6 +115,36 @@ class SubspaceHelperBase { auto begin() const { return self().begin(); } auto end() const { return self().end(); } + bool contains(std::uint8_t index) const { + return std::find(begin(), end(), index) != end(); + } + std::size_t indexOf(std::uint8_t index) const { + auto it = std::find(begin(), end(), index); + return it != end() ? std::distance(begin(), it) : kFullSize; + } + + template + ActsVector expandVector( + const Eigen::DenseBase& vector) const { + ActsVector result = ActsVector::Zero(); + for (auto [i, index] : enumerate(*this)) { + result(index) = vector(i); + } + return result; + } + + template + FullSquareMatrix expandMatrix( + const Eigen::DenseBase& matrix) const { + FullSquareMatrix result = FullSquareMatrix::Zero(); + for (auto [i, indexI] : enumerate(*this)) { + for (auto [j, indexJ] : enumerate(*this)) { + result(indexI, indexJ) = matrix(i, j); + } + } + return result; + } + FullSquareMatrix fullProjector() const { FullSquareMatrix result = FullSquareMatrix::Zero(); for (auto [i, index] : enumerate(*this)) { @@ -168,6 +198,7 @@ class VariableSubspaceHelper bool empty() const { return m_indices.empty(); } std::size_t size() const { return m_indices.size(); } + const Container& indices() const { return m_indices; } IndexType operator[](std::size_t i) const { return m_indices[i]; } @@ -215,6 +246,7 @@ class FixedSubspaceHelper bool empty() const { return m_indices.empty(); } std::size_t size() const { return m_indices.size(); } + const Container& indices() const { return m_indices; } IndexType operator[](std::uint32_t i) const { return m_indices[i]; } diff --git a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/MeasurementCreation.hpp b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/MeasurementCreation.hpp index 3d9476815c9..e168858cfd1 100644 --- a/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/MeasurementCreation.hpp +++ b/Examples/Algorithms/Digitization/include/ActsExamples/Digitization/MeasurementCreation.hpp @@ -1,6 +1,6 @@ // This file is part of the Acts project. // -// Copyright (C) 2021 CERN for the benefit of the Acts project +// Copyright (C) 2021-2024 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 @@ -40,9 +40,10 @@ struct DigitizedParameters { /// /// To be used also by the e I/O system /// -/// @return a variant measurement -Measurement createMeasurement(const DigitizedParameters& dParams, - const IndexSourceLink& isl) noexcept(false); +/// @return the measurement proxy +ActsExamples::VariableBoundMeasurementProxy createMeasurement( + MeasurementContainer& container, const DigitizedParameters& dParams, + const IndexSourceLink& isl) noexcept(false); /// Construct the constituents of a measurement. /// diff --git a/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp b/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp index f3b04ac0aff..3ac84f45bac 100644 --- a/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp +++ b/Examples/Algorithms/Digitization/src/DigitizationAlgorithm.cpp @@ -1,6 +1,6 @@ // This file is part of the Acts project. // -// Copyright (C) 2021 CERN for the benefit of the Acts project +// Copyright (C) 2021-2024 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 @@ -268,8 +268,7 @@ ActsExamples::ProcessCode ActsExamples::DigitizationAlgorithm::execute( // be added at the end. sourceLinks.insert(sourceLinks.end(), sourceLink); - measurements.emplace_back( - createMeasurement(dParameters, sourceLink)); + createMeasurement(measurements, dParameters, sourceLink); clusters.emplace_back(std::move(dParameters.cluster)); // this digitization does hit merging so there can be more than one // mapping entry for each digitized hit. diff --git a/Examples/Algorithms/Digitization/src/MeasurementCreation.cpp b/Examples/Algorithms/Digitization/src/MeasurementCreation.cpp index 7338b431f8c..5a9aee23c70 100644 --- a/Examples/Algorithms/Digitization/src/MeasurementCreation.cpp +++ b/Examples/Algorithms/Digitization/src/MeasurementCreation.cpp @@ -1,6 +1,6 @@ // This file is part of the Acts project. // -// Copyright (C) 2021 CERN for the benefit of the Acts project +// Copyright (C) 2021-2024 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 @@ -8,36 +8,35 @@ #include "ActsExamples/Digitization/MeasurementCreation.hpp" +#include "Acts/EventData/MeasurementHelpers.hpp" #include "Acts/EventData/SourceLink.hpp" #include "ActsExamples/EventData/IndexSourceLink.hpp" +#include "ActsExamples/EventData/Measurement.hpp" #include #include #include -ActsExamples::Measurement ActsExamples::createMeasurement( - const DigitizedParameters& dParams, const IndexSourceLink& isl) { +ActsExamples::VariableBoundMeasurementProxy ActsExamples::createMeasurement( + MeasurementContainer& container, const DigitizedParameters& dParams, + const IndexSourceLink& isl) { Acts::SourceLink sl{isl}; - switch (dParams.indices.size()) { - case 1u: { - auto [indices, par, cov] = measurementConstituents<1>(dParams); - return ActsExamples::Measurement(std::move(sl), indices, par, cov); - } - case 2u: { - auto [indices, par, cov] = measurementConstituents<2>(dParams); - return ActsExamples::Measurement(std::move(sl), indices, par, cov); - }; - case 3u: { - auto [indices, par, cov] = measurementConstituents<3>(dParams); - return ActsExamples::Measurement(std::move(sl), indices, par, cov); - }; - case 4u: { - auto [indices, par, cov] = measurementConstituents<4>(dParams); - return ActsExamples::Measurement(std::move(sl), indices, par, cov); - }; - default: - std::string errorMsg = "Invalid/mismatching measurement dimension: " + - std::to_string(dParams.indices.size()); - throw std::runtime_error(errorMsg.c_str()); + + if (dParams.indices.size() > 4u) { + std::string errorMsg = "Invalid/mismatching measurement dimension: " + + std::to_string(dParams.indices.size()); + throw std::runtime_error(errorMsg.c_str()); } + + return Acts::visit_measurement( + dParams.indices.size(), [&](auto dim) -> VariableBoundMeasurementProxy { + auto [indices, par, cov] = measurementConstituents(dParams); + FixedBoundMeasurementProxy measurement = + container.makeMeasurement(); + measurement.setSourceLink(sl); + measurement.setSubspaceIndices(indices); + measurement.parameters() = par; + measurement.covariance() = cov; + return measurement; + }); } diff --git a/Examples/Algorithms/TrackFinding/src/HoughTransformSeeder.cpp b/Examples/Algorithms/TrackFinding/src/HoughTransformSeeder.cpp index 25d9d7f2e25..3c16d146d65 100644 --- a/Examples/Algorithms/TrackFinding/src/HoughTransformSeeder.cpp +++ b/Examples/Algorithms/TrackFinding/src/HoughTransformSeeder.cpp @@ -529,7 +529,8 @@ void ActsExamples::HoughTransformSeeder::addMeasurements( // are transformed to the bound space where we do know their location. // if the local parameters are not measured, this results in a // zero location, which is a reasonable default fall-back. - const auto& measurement = measurements[sourceLink.index()]; + const ConstVariableBoundMeasurementProxy measurement = + measurements.getMeasurement(sourceLink.index()); assert(measurement.contains(Acts::eBoundLoc0) && "Measurement does not contain the required bound loc0"); diff --git a/Examples/Algorithms/TrackFinding/src/SpacePointMaker.cpp b/Examples/Algorithms/TrackFinding/src/SpacePointMaker.cpp index 49802b57087..0605e1b4bc4 100644 --- a/Examples/Algorithms/TrackFinding/src/SpacePointMaker.cpp +++ b/Examples/Algorithms/TrackFinding/src/SpacePointMaker.cpp @@ -126,7 +126,8 @@ ActsExamples::ProcessCode ActsExamples::SpacePointMaker::execute( spOpt.paramCovAccessor = [&measurements](Acts::SourceLink slink) { const auto islink = slink.get(); - const auto& meas = measurements[islink.index()]; + const ConstVariableBoundMeasurementProxy meas = + measurements.getMeasurement(islink.index()); return std::make_pair(meas.fullParameters(), meas.fullCovariance()); }; diff --git a/Examples/Algorithms/TrackFitting/src/TrackFittingAlgorithm.cpp b/Examples/Algorithms/TrackFitting/src/TrackFittingAlgorithm.cpp index f80f20570c5..0a352d71fe6 100644 --- a/Examples/Algorithms/TrackFitting/src/TrackFittingAlgorithm.cpp +++ b/Examples/Algorithms/TrackFitting/src/TrackFittingAlgorithm.cpp @@ -18,6 +18,7 @@ #include "Acts/Surfaces/PerigeeSurface.hpp" #include "Acts/Surfaces/Surface.hpp" #include "Acts/Utilities/Result.hpp" +#include "ActsExamples/EventData/Measurement.hpp" #include "ActsExamples/EventData/MeasurementCalibration.hpp" #include "ActsExamples/EventData/ProtoTrack.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" @@ -126,7 +127,8 @@ ActsExamples::ProcessCode ActsExamples::TrackFittingAlgorithm::execute( // Fill the source links via their indices from the container for (auto hitIndex : protoTrack) { - const auto& measurement = measurements.at(hitIndex); + ConstVariableBoundMeasurementProxy measurement = + measurements.getMeasurement(hitIndex); trackSourceLinks.push_back(measurement.sourceLink()); } diff --git a/Examples/Framework/CMakeLists.txt b/Examples/Framework/CMakeLists.txt index bfe33f2e8e6..692db8f2f15 100644 --- a/Examples/Framework/CMakeLists.txt +++ b/Examples/Framework/CMakeLists.txt @@ -5,6 +5,7 @@ set(ActsExamplesFramework_SOURCES) add_library( ActsExamplesFramework SHARED + src/EventData/Measurement.cpp src/EventData/MeasurementCalibration.cpp src/EventData/ScalingCalibrator.cpp src/Framework/IAlgorithm.cpp diff --git a/Examples/Framework/ML/src/NeuralCalibrator.cpp b/Examples/Framework/ML/src/NeuralCalibrator.cpp index 77af3920a6a..54003b3bfc1 100644 --- a/Examples/Framework/ML/src/NeuralCalibrator.cpp +++ b/Examples/Framework/ML/src/NeuralCalibrator.cpp @@ -1,6 +1,6 @@ // This file is part of the Acts project. // -// Copyright (C) 2023 CERN for the benefit of the Acts project +// Copyright (C) 2023-2024 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 @@ -106,7 +106,8 @@ void ActsExamples::NeuralCalibrator::calibrate( const Acts::Surface& referenceSurface = trackState.referenceSurface(); auto trackParameters = trackState.parameters(); - const auto& measurement = measurements[idxSourceLink.index()]; + const ConstVariableBoundMeasurementProxy measurement = + measurements.getMeasurement(idxSourceLink.index()); assert(measurement.contains(Acts::eBoundLoc0) && "Measurement does not contain the required bound loc0"); @@ -171,21 +172,24 @@ void ActsExamples::NeuralCalibrator::calibrate( std::size_t iLoc0 = m_nComponents + iMax * 2; std::size_t iVar0 = 3 * m_nComponents + iMax * 2; - Measurement measurementCopy = measurement; - measurementCopy.parameters()[boundLoc0] = output[iLoc0]; - measurementCopy.parameters()[boundLoc1] = output[iLoc0 + 1]; - measurementCopy.covariance()(boundLoc0, boundLoc0) = output[iVar0]; - measurementCopy.covariance()(boundLoc1, boundLoc1) = output[iVar0 + 1]; - Acts::visit_measurement(measurement.size(), [&](auto N) -> void { constexpr std::size_t kMeasurementSize = decltype(N)::value; + const ConstFixedBoundMeasurementProxy fixedMeasurement = + measurement; + + Acts::ActsVector calibratedParameters = + fixedMeasurement.parameters(); + Acts::ActsSquareMatrix calibratedCovariance = + fixedMeasurement.covariance(); + + calibratedParameters[boundLoc0] = output[iLoc0]; + calibratedParameters[boundLoc1] = output[iLoc0 + 1]; + calibratedCovariance(boundLoc0, boundLoc0) = output[iVar0]; + calibratedCovariance(boundLoc1, boundLoc1) = output[iVar0 + 1]; trackState.allocateCalibrated(kMeasurementSize); - trackState.calibrated() = - measurementCopy.parameters(); - trackState.calibratedCovariance() = - measurementCopy.covariance(); - trackState.setSubspaceIndices( - measurementCopy.subspaceIndices()); + trackState.calibrated() = calibratedParameters; + trackState.calibratedCovariance() = calibratedCovariance; + trackState.setSubspaceIndices(fixedMeasurement.subspaceIndices()); }); } diff --git a/Examples/Framework/include/ActsExamples/EventData/Measurement.hpp b/Examples/Framework/include/ActsExamples/EventData/Measurement.hpp index 87c4c546c08..31193f6818d 100644 --- a/Examples/Framework/include/ActsExamples/EventData/Measurement.hpp +++ b/Examples/Framework/include/ActsExamples/EventData/Measurement.hpp @@ -8,6 +8,7 @@ #pragma once +#include "Acts/Definitions/Algebra.hpp" #include "Acts/Definitions/TrackParametrization.hpp" #include "Acts/EventData/MeasurementHelpers.hpp" #include "Acts/EventData/SourceLink.hpp" @@ -28,253 +29,460 @@ namespace ActsExamples { -/// A measurement of a variable-size subspace of the full parameters. +template +class MeasurementProxyBase; +template +class FixedMeasurementProxy; +template +class VariableMeasurementProxy; + +template +using FixedBoundMeasurementProxy = + FixedMeasurementProxy; +template +using ConstFixedBoundMeasurementProxy = + FixedMeasurementProxy; +using VariableBoundMeasurementProxy = + VariableMeasurementProxy; +using ConstVariableBoundMeasurementProxy = + VariableMeasurementProxy; + +/// @brief A container to store and access measurements /// -/// @tparam indices_t Parameter index type, determines the full parameter space +/// This container stores measurements of different sizes and provides +/// access to them through fixed-size and variable-size proxies. /// -/// The measurement intentionally does not store a pointer/reference to the -/// reference object in the geometry hierarchy, i.e. the surface or volume. The -/// reference object can already be identified via the geometry identifier -/// provided by the source link. Since a measurement **must** be anchored within -/// the geometry hierarchy, all measurement surfaces and volumes **must** -/// provide valid geometry identifiers. In all use-cases, e.g. Kalman filtering, -/// a pointer/reference to the reference object is available before the -/// measurement is accessed; e.g. the propagator provides the surface pointer -/// during navigation, which is then used to lookup possible measurements. -/// -/// The pointed-to geometry object would differ depending on the parameter type. -/// This means either, that there needs to be an additional variable type or -/// that a pointer to a base object is stored (requiring a `dynamic_cast` later -/// on). Both variants add additional complications. Since the geometry object -/// is not required anyway (as discussed above), not storing it removes all -/// these complications altogether. -template -class VariableSizeMeasurement { +/// The measurements are stored densely in a flat buffer and the proxies +/// provide access to the individual measurements. +class MeasurementContainer { public: - static constexpr std::size_t kFullSize = - Acts::detail::kParametersSize; - - using Scalar = Acts::ActsScalar; + using Index = std::size_t; + template + using FixedProxy = FixedMeasurementProxy; + template + using ConstFixedProxy = FixedMeasurementProxy; + using VariableProxy = VariableMeasurementProxy; + using ConstVariableProxy = VariableMeasurementProxy; + + MeasurementContainer(); + + /// @brief Get the number of measurements + /// @return The number of measurements + std::size_t size() const; + + /// @brief Reserve space for a number of measurements + /// @param size The number of measurements to reserve space for + void reserve(std::size_t size); + + /// @brief Add a measurement of a given size + /// @param size The size of the measurement + /// @return The index of the added measurement + Index addMeasurement(std::uint8_t size); + + /// @brief Get a variable-size measurement proxy + /// @param index The index of the measurement + /// @return The variable-size measurement proxy + VariableProxy getMeasurement(Index index); + /// @brief Get a const variable-size measurement proxy + /// @param index The index of the measurement + /// @return The const variable-size measurement proxy + ConstVariableProxy getMeasurement(Index index) const; + + /// @brief Get a fixed-size measurement proxy + /// @tparam Size The size of the measurement + /// @param index The index of the measurement + /// @return The fixed-size measurement proxy + template + FixedProxy getMeasurement(Index index) { + return FixedProxy{*this, index}; + } + /// @brief Get a const fixed-size measurement proxy + /// @tparam Size The size of the measurement + /// @param index The index of the measurement + /// @return The const fixed-size measurement proxy + template + ConstFixedProxy getMeasurement(Index index) const { + return ConstFixedProxy{*this, index}; + } - using SubspaceIndex = std::uint8_t; - using SubspaceIndices = - boost::container::static_vector; - - /// Vector type containing for measured parameter values. - template - using ParametersVector = Eigen::Matrix; - template - using ParametersVectorMap = Eigen::Map>; - template - using ConstParametersVectorMap = Eigen::Map>; - using EffectiveParametersVector = Eigen::Matrix; - using EffectiveParametersVectorMap = Eigen::Map; - using ConstEffectiveParametersVectorMap = - Eigen::Map; - - /// Matrix type for the measurement covariance. - template - using CovarianceMatrix = Eigen::Matrix; - template - using CovarianceMatrixMap = Eigen::Map>; - template - using ConstCovarianceMatrixMap = Eigen::Map>; - using EffectiveCovarianceMatrix = - Eigen::Matrix; - using EffectiveCovarianceMatrixMap = Eigen::Map; - using ConstEffectiveCovarianceMatrixMap = - Eigen::Map; - - using FullParametersVector = Acts::ActsVector; - using FullCovarianceMatrix = Acts::ActsSquareMatrix; - - using ProjectionMatrix = Eigen::Matrix; - using ExpansionMatrix = Eigen::Matrix; - - /// Construct from source link, subset indices, and measured data. - /// - /// @tparam parameters_t Input parameters vector type - /// @tparam covariance_t Input covariance matrix type - /// @param source The link that connects to the underlying detector readout - /// @param subspaceIndices Which parameters are measured - /// @param params Measured parameters values - /// @param cov Measured parameters covariance - /// - /// @note The indices must be ordered and must describe/match the content - /// of parameters and covariance. - template - VariableSizeMeasurement( - Acts::SourceLink source, - const std::array& subspaceIndices, - const Eigen::MatrixBase& params, - const Eigen::MatrixBase& cov) - : m_source(std::move(source)) { - static_assert(kSize == parameters_t::RowsAtCompileTime, - "Parameter size mismatch"); - static_assert(kSize == covariance_t::RowsAtCompileTime, - "Covariance rows mismatch"); - static_assert(kSize == covariance_t::ColsAtCompileTime, - "Covariance cols mismatch"); - - m_subspaceIndices.resize(subspaceIndices.size()); - std::transform(subspaceIndices.begin(), subspaceIndices.end(), - m_subspaceIndices.begin(), [](auto index) { - return static_cast(index); - }); - - parameters() = params; - covariance() = cov; + /// @brief Make a measurement of a given size + /// @param size The size of the measurement + /// @return The variable-size measurement proxy + VariableProxy makeMeasurement(std::uint8_t size); + /// @brief Make a fixed-size measurement + /// @tparam Size The size of the measurement + /// @return The fixed-size measurement proxy + template + FixedProxy makeMeasurement() { + return getMeasurement(addMeasurement(Size)); } - /// A measurement can only be constructed with valid parameters. - VariableSizeMeasurement() = delete; - VariableSizeMeasurement(const VariableSizeMeasurement&) = default; - VariableSizeMeasurement(VariableSizeMeasurement&&) = default; - ~VariableSizeMeasurement() = default; - VariableSizeMeasurement& operator=(const VariableSizeMeasurement&) = default; - VariableSizeMeasurement& operator=(VariableSizeMeasurement&&) = default; - /// Source link that connects to the underlying detector readout. - const Acts::SourceLink& sourceLink() const { return m_source; } + template + class IteratorImpl { + public: + using value_type = + std::conditional_t; + using reference = value_type; + using pointer = value_type*; + using difference_type = std::ptrdiff_t; + using iterator_category = std::forward_iterator_tag; + + using Container = std::conditional_t; + + IteratorImpl(Container& container, std::size_t index) + : m_container(container), m_index(index) {} - constexpr std::size_t size() const { return m_subspaceIndices.size(); } + reference operator*() const { return m_container.getMeasurement(m_index); } + + pointer operator->() const { return &operator*(); } + + IteratorImpl& operator++() { + ++m_index; + return *this; + } + + IteratorImpl operator++(int) { + auto copy = *this; + ++*this; + return copy; + } + + bool operator==(const IteratorImpl& other) const { + return m_index == other.m_index; + } - /// Check if a specific parameter is part of this measurement. + bool operator!=(const IteratorImpl& other) const { + return !(*this == other); + } + + private: + Container& m_container; + Index m_index; + }; + + using iterator = IteratorImpl; + using const_iterator = IteratorImpl; + + iterator begin(); + iterator end(); + const_iterator begin() const; + const_iterator end() const; + const_iterator cbegin() const; + const_iterator cend() const; + + public: + struct MeasurementEntry { + std::size_t subspaceIndexOffset{}; + std::size_t parameterOffset{}; + std::size_t covarianceOffset{}; + std::uint8_t size{}; + }; + + std::vector m_entries; + + std::vector> m_sourceLinks; + std::vector m_subspaceIndices; + std::vector m_parameters; + std::vector m_covariances; +}; + +/// @brief Base class for measurement proxies +/// +/// This class provides common functionality for fixed-size and variable-size +/// measurement proxies. +/// +/// @tparam Derived The derived measurement proxy class +/// @tparam FullSize The full size of the measurement +/// @tparam ReadOnly Whether the proxy is read-only +template +class MeasurementProxyBase { + public: + using Index = MeasurementContainer::Index; + using SubspaceIndex = std::uint8_t; + using Scalar = double; + + using FullVector = Acts::ActsVector; + using FullSquareMatrix = Acts::ActsSquareMatrix; + + using Container = std::conditional_t; + + MeasurementProxyBase(Container& container_, Index index_) + : m_container(&container_), m_index(index_) {} + template + MeasurementProxyBase( + const MeasurementProxyBase& other) + requires(ReadOnly == OtherReadOnly || ReadOnly) + : m_container(&other.container()), m_index(other.index()) {} + + /// @brief Get the container of the measurement + /// @return The container of the measurement + Container& container() const { return *m_container; } + /// @brief Get the index of the measurement + /// @return The index of the measurement + Index index() const { return m_index; } + + /// @brief Get the size of the measurement + /// @return The size of the measurement + std::size_t size() const { return container().m_entries.at(m_index).size; } + + /// @brief Check if the measurement contains a subspace index + /// @param i The subspace index + /// @return True if the measurement contains the subspace index + template bool contains(indices_t i) const { - return std::find(m_subspaceIndices.begin(), m_subspaceIndices.end(), i) != - m_subspaceIndices.end(); + return self().subspaceHelper().contains(i); } + /// @brief Get the index of a subspace index in the measurement + /// @param i The subspace index + /// @return The index of the subspace index in the measurement + template std::size_t indexOf(indices_t i) const { - auto it = std::find(m_subspaceIndices.begin(), m_subspaceIndices.end(), i); - assert(it != m_subspaceIndices.end()); - return std::distance(m_subspaceIndices.begin(), it); + return self().subspaceHelper().indexOf(i); } - /// The measurement indices - const SubspaceIndices& subspaceIndices() const { return m_subspaceIndices; } + /// @brief Set the source link of the measurement + /// @param sourceLink The source link + void setSourceLink(const Acts::SourceLink& sourceLink) + requires(!ReadOnly) + { + container().m_sourceLinks.at(m_index) = sourceLink; + } - template - Acts::SubspaceIndices subspaceIndices() const { - assert(dim == size()); - Acts::SubspaceIndices result; - std::copy(m_subspaceIndices.begin(), m_subspaceIndices.end(), - result.begin()); - return result; + /// @brief Get the source link of the measurement + /// @return The source link + const Acts::SourceLink& sourceLink() const { + return container().m_sourceLinks.at(m_index).value(); } - Acts::BoundSubspaceIndices boundSubsetIndices() const - requires(std::is_same_v) + /// @brief Set the subspace indices of the measurement + /// @param indices The subspace indices + template + void setSubspaceIndices(const IndexContainer& indices) + requires(!ReadOnly) { - Acts::BoundSubspaceIndices result = Acts::kBoundSubspaceIndicesInvalid; - std::copy(m_subspaceIndices.begin(), m_subspaceIndices.end(), - result.begin()); - return result; + assert(checkSubspaceIndices(indices, FullSize, size()) && + "Invalid indices"); + std::transform(indices.begin(), indices.end(), + self().subspaceIndexVector().begin(), + [](auto index) { return static_cast(index); }); } - template - ConstParametersVectorMap parameters() const { - assert(dim == size()); - return ConstParametersVectorMap{m_params.data()}; + /// @brief Get the measurement as a full-size vector + /// @return The full-size measurement vector + FullVector fullParameters() const { + return self().subspaceHelper().expandVector(self().parameters()); } - template - ParametersVectorMap parameters() { - assert(dim == size()); - return ParametersVectorMap{m_params.data()}; - } - ConstEffectiveParametersVectorMap parameters() const { - return ConstEffectiveParametersVectorMap{m_params.data(), - static_cast(size())}; + + /// @brief Get the covariance as a full-size square matrix + /// @return The full-size covariance matrix + FullSquareMatrix fullCovariance() const { + return self().subspaceHelper().expandMatrix(self().covariance()); } - EffectiveParametersVectorMap parameters() { - return EffectiveParametersVectorMap{m_params.data(), - static_cast(size())}; + + /// @brief Copy the data from another measurement + /// @tparam OtherDerived The derived measurement proxy class of the other + /// measurement + /// @param other The other measurement proxy + template + void copyFrom(const OtherDerived& other) + requires(!ReadOnly) + { + assert(size() == other.size() && "Size mismatch"); + setSourceLink(other.sourceLink()); + self().subspaceIndexVector() = other.subspaceIndexVector(); + self().parameters() = other.parameters(); + self().covariance() = other.covariance(); } - template - ConstCovarianceMatrixMap covariance() const { - assert(dim == size()); - return ConstCovarianceMatrixMap{m_cov.data()}; + protected: + Derived& self() { return static_cast(*this); } + const Derived& self() const { return static_cast(*this); } + + Container* m_container; + Index m_index; +}; + +/// @brief Fixed-size measurement proxy +/// +/// This class provides access to a fixed-size measurement in a measurement +/// container. +/// +/// @tparam FullSize The full size of the measurement +/// @tparam Size The size of the measurement +/// @tparam ReadOnly Whether the proxy is read-only +template +class FixedMeasurementProxy + : public MeasurementProxyBase< + FixedMeasurementProxy, FullSize, ReadOnly> { + public: + using Base = + MeasurementProxyBase, + FullSize, ReadOnly>; + using Index = typename Base::Index; + using SubspaceIndex = typename Base::SubspaceIndex; + using Scalar = typename Base::Scalar; + using Container = typename Base::Container; + + using SubspaceHelper = Acts::FixedSubspaceHelper; + + using SubspaceVector = Eigen::Matrix; + using SubspaceVectorMap = + std::conditional_t, + Eigen::Map>; + + using ParametersVector = Eigen::Matrix; + using ParametersVectorMap = + std::conditional_t, + Eigen::Map>; + + using CovarianceMatrix = Eigen::Matrix; + using CovarianceMatrixMap = + std::conditional_t, + Eigen::Map>; + + FixedMeasurementProxy(Container& container_, Index index_) + : Base(container_, index_) { + assert(container().m_entries.at(index()).size == Size && "Size mismatch"); } - template - CovarianceMatrixMap covariance() { - assert(dim == size()); - return CovarianceMatrixMap{m_cov.data()}; + template + FixedMeasurementProxy( + const MeasurementProxyBase& other) + requires(ReadOnly == OtherReadOnly || ReadOnly) + : Base(other) { + assert(container().m_entries.at(index()).size == Size && "Size mismatch"); } - ConstEffectiveCovarianceMatrixMap covariance() const { - return ConstEffectiveCovarianceMatrixMap{m_cov.data(), - static_cast(size()), - static_cast(size())}; + + using Base::container; + using Base::index; + + /// @brief Get the size of the measurement + /// @return The size of the measurement + static constexpr std::size_t size() { return Size; } + + /// @brief Get the subspace helper for the measurement + /// @return The subspace helper + SubspaceHelper subspaceHelper() const { + return SubspaceHelper{subspaceIndexVector()}; } - EffectiveCovarianceMatrixMap covariance() { - return EffectiveCovarianceMatrixMap{m_cov.data(), - static_cast(size()), - static_cast(size())}; + + /// @brief Get the subspace indices of the measurement + /// @return The subspace indices + Acts::SubspaceIndices subspaceIndices() const { + return subspaceHelper().indices(); } - FullParametersVector fullParameters() const { - FullParametersVector result = FullParametersVector::Zero(); - for (std::size_t i = 0; i < size(); ++i) { - result[m_subspaceIndices[i]] = parameters()[i]; - } - return result; + /// @brief Get the subspace index vector of the measurement + /// @return The subspace index vector + SubspaceVectorMap subspaceIndexVector() const { + return SubspaceVectorMap{ + container().m_subspaceIndices.data() + + container().m_entries.at(index()).subspaceIndexOffset}; } - FullCovarianceMatrix fullCovariance() const { - FullCovarianceMatrix result = FullCovarianceMatrix::Zero(); - for (std::size_t i = 0; i < size(); ++i) { - for (std::size_t j = 0; j < size(); ++j) { - result(m_subspaceIndices[i], m_subspaceIndices[j]) = covariance()(i, j); - } - } - return result; + /// @brief Get the parameters of the measurement + /// @return The parameters + ParametersVectorMap parameters() const { + return ParametersVectorMap{ + container().m_parameters.data() + + container().m_entries.at(index()).parameterOffset}; } - private: - Acts::SourceLink m_source; - SubspaceIndices m_subspaceIndices; - std::array m_params{}; - std::array m_cov{}; + /// @brief Get the covariance of the measurement + /// @return The covariance + CovarianceMatrixMap covariance() const { + return CovarianceMatrixMap{ + container().m_covariances.data() + + container().m_entries.at(index()).covarianceOffset}; + } }; -/// Construct a variable-size measurement for the given indices. -/// -/// @tparam parameters_t Input parameters vector type -/// @tparam covariance_t Input covariance matrix type -/// @tparam indices_t Parameter index type, determines the full parameter space -/// @tparam tail_indices_t Helper types required to support variadic arguments; -/// all types must be convertibale to `indices_t`. -/// @param source The link that connects to the underlying detector readout -/// @param params Measured parameters values -/// @param cov Measured parameters covariance -/// @param index0 Required parameter index, measurement must be at least 1d -/// @param tailIndices Additional parameter indices for larger measurements -/// @return Variable-size measurement w/ the correct type and given inputs +/// @brief Variable-size measurement proxy /// -/// @note The indices must be ordered and must be consistent with the content of -/// parameters and covariance. -template -VariableSizeMeasurement makeVariableSizeMeasurement( - Acts::SourceLink source, const Eigen::MatrixBase& params, - const Eigen::MatrixBase& cov, indices_t index0, - tail_indices_t... tailIndices) { - using IndexContainer = std::array; - return {std::move(source), IndexContainer{index0, tailIndices...}, params, - cov}; -} - -/// Type that can hold all possible bound measurements. -using BoundVariableMeasurement = VariableSizeMeasurement; - -/// Variable measurement type that can contain all possible combinations. -using Measurement = BoundVariableMeasurement; - -/// Container of measurements. +/// This class provides access to a variable-size measurement in a measurement +/// container. /// -/// In contrast to the source links, the measurements themself must not be -/// orderable. The source links stored in the measurements are treated -/// as opaque here and no ordering is enforced on the stored measurements. -using MeasurementContainer = std::vector; +/// @tparam FullSize The full size of the measurement +/// @tparam ReadOnly Whether the proxy is read-only +template +class VariableMeasurementProxy + : public MeasurementProxyBase, + FullSize, ReadOnly> { + public: + using Base = + MeasurementProxyBase, + FullSize, ReadOnly>; + using Index = typename Base::Index; + using SubspaceIndex = typename Base::SubspaceIndex; + using Scalar = typename Base::Scalar; + using Container = typename Base::Container; + + using SubspaceHelper = Acts::VariableSubspaceHelper; + + using SubspaceVector = Eigen::Matrix; + using SubspaceVectorMap = + std::conditional_t, + Eigen::Map>; + + using ParametersVector = Eigen::Matrix; + using ParametersVectorMap = + std::conditional_t, + Eigen::Map>; + + using CovarianceMatrix = + Eigen::Matrix; + using CovarianceMatrixMap = + std::conditional_t, + Eigen::Map>; + + VariableMeasurementProxy(Container& container_, Index index_) + : Base(container_, index_) {} + template + VariableMeasurementProxy( + const MeasurementProxyBase& other) + requires(ReadOnly == OtherReadOnly || ReadOnly) + : Base(other) {} + + using Base::container; + using Base::index; + + /// @brief Get the subspace helper for the measurement + /// @return The subspace helper + SubspaceHelper subspaceHelper() const { + return SubspaceHelper{subspaceIndexVector()}; + } + + /// @brief Get the subspace indices of the measurement + /// @return The subspace indices + SubspaceVectorMap subspaceIndexVector() const { + const auto size = static_cast(this->size()); + return SubspaceVectorMap{ + container().m_subspaceIndices.data() + + container().m_entries.at(index()).subspaceIndexOffset, + size}; + } + + /// @brief Get the parameters of the measurement + /// @return The parameters + ParametersVectorMap parameters() const { + const auto size = static_cast(this->size()); + return ParametersVectorMap{ + container().m_parameters.data() + + container().m_entries.at(index()).parameterOffset, + size}; + } + + /// @brief Get the covariance of the measurement + /// @return The covariance + CovarianceMatrixMap covariance() const { + const auto size = static_cast(this->size()); + return CovarianceMatrixMap{ + container().m_covariances.data() + + container().m_entries.at(index()).covarianceOffset, + size, size}; + } +}; } // namespace ActsExamples diff --git a/Examples/Framework/src/EventData/Measurement.cpp b/Examples/Framework/src/EventData/Measurement.cpp new file mode 100644 index 00000000000..d9ae3520d86 --- /dev/null +++ b/Examples/Framework/src/EventData/Measurement.cpp @@ -0,0 +1,75 @@ +// This file is part of the Acts project. +// +// Copyright (C) 2024 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 http://mozilla.org/MPL/2.0/. + +#include "ActsExamples/EventData/Measurement.hpp" + +namespace ActsExamples { + +MeasurementContainer::MeasurementContainer() = default; + +std::size_t MeasurementContainer::size() const { + return m_entries.size(); +} + +void MeasurementContainer::reserve(std::size_t size) { + m_sourceLinks.reserve(size); + m_subspaceIndices.reserve(size * 2); + m_parameters.reserve(size * 2); + m_covariances.reserve(size * 2 * 2); +} + +std::size_t MeasurementContainer::addMeasurement(std::uint8_t size) { + m_entries.push_back({m_subspaceIndices.size(), m_parameters.size(), + m_covariances.size(), size}); + m_sourceLinks.emplace_back(); + m_subspaceIndices.resize(m_subspaceIndices.size() + size); + m_parameters.resize(m_parameters.size() + size); + m_covariances.resize(m_covariances.size() + size * size); + return m_entries.size() - 1; +} + +MeasurementContainer::VariableProxy MeasurementContainer::getMeasurement( + std::size_t index) { + return VariableProxy{*this, index}; +} + +MeasurementContainer::ConstVariableProxy MeasurementContainer::getMeasurement( + std::size_t index) const { + return ConstVariableProxy{*this, index}; +} + +MeasurementContainer::VariableProxy MeasurementContainer::makeMeasurement( + std::uint8_t size) { + return getMeasurement(addMeasurement(size)); +} + +MeasurementContainer::iterator MeasurementContainer::begin() { + return iterator{*this, 0}; +} + +MeasurementContainer::iterator MeasurementContainer::end() { + return iterator{*this, m_entries.size()}; +} + +MeasurementContainer::const_iterator MeasurementContainer::begin() const { + return const_iterator{*this, 0}; +} + +MeasurementContainer::const_iterator MeasurementContainer::end() const { + return const_iterator{*this, m_entries.size()}; +} + +MeasurementContainer::const_iterator MeasurementContainer::cbegin() const { + return const_iterator{*this, 0}; +} + +MeasurementContainer::const_iterator MeasurementContainer::cend() const { + return const_iterator{*this, m_entries.size()}; +} + +} // namespace ActsExamples diff --git a/Examples/Framework/src/EventData/MeasurementCalibration.cpp b/Examples/Framework/src/EventData/MeasurementCalibration.cpp index 560593dbd1f..84b1c5a2d45 100644 --- a/Examples/Framework/src/EventData/MeasurementCalibration.cpp +++ b/Examples/Framework/src/EventData/MeasurementCalibration.cpp @@ -6,11 +6,12 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +#include "ActsExamples/EventData/MeasurementCalibration.hpp" + #include "Acts/Definitions/TrackParametrization.hpp" #include "Acts/EventData/SourceLink.hpp" #include "ActsExamples/EventData/IndexSourceLink.hpp" #include "ActsExamples/EventData/Measurement.hpp" -#include #include #include @@ -31,18 +32,19 @@ void ActsExamples::PassThroughCalibrator::calibrate( assert((idxSourceLink.index() < measurements.size()) && "Source link index is outside the container bounds"); - const auto& measurement = measurements[idxSourceLink.index()]; + const ConstVariableBoundMeasurementProxy measurement = + measurements.getMeasurement(idxSourceLink.index()); Acts::visit_measurement(measurement.size(), [&](auto N) -> void { constexpr std::size_t kMeasurementSize = decltype(N)::value; + const ConstFixedBoundMeasurementProxy fixedMeasurement = + measurement; trackState.allocateCalibrated(kMeasurementSize); - trackState.calibrated() = - measurement.parameters(); + trackState.calibrated() = fixedMeasurement.parameters(); trackState.calibratedCovariance() = - measurement.covariance(); - trackState.setSubspaceIndices( - measurement.subspaceIndices()); + fixedMeasurement.covariance(); + trackState.setSubspaceIndices(fixedMeasurement.subspaceIndices()); }); } diff --git a/Examples/Framework/src/EventData/ScalingCalibrator.cpp b/Examples/Framework/src/EventData/ScalingCalibrator.cpp index 805d8cdef15..183dc3cb7d0 100644 --- a/Examples/Framework/src/EventData/ScalingCalibrator.cpp +++ b/Examples/Framework/src/EventData/ScalingCalibrator.cpp @@ -1,6 +1,6 @@ // This file is part of the Acts project. // -// Copyright (C) 2023 CERN for the benefit of the Acts project +// Copyright (C) 2023-2024 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 @@ -151,7 +151,8 @@ void ActsExamples::ScalingCalibrator::calibrate( const Cluster& cl = clusters->at(idxSourceLink.index()); ConstantTuple ct = m_calib_maps.at(mgid).at(cl.sizeLoc0, cl.sizeLoc1); - const auto& measurement = measurements[idxSourceLink.index()]; + const ConstVariableBoundMeasurementProxy measurement = + measurements.getMeasurement(idxSourceLink.index()); assert(measurement.contains(Acts::eBoundLoc0) && "Measurement does not contain the required bound loc0"); @@ -161,21 +162,24 @@ void ActsExamples::ScalingCalibrator::calibrate( auto boundLoc0 = measurement.indexOf(Acts::eBoundLoc0); auto boundLoc1 = measurement.indexOf(Acts::eBoundLoc1); - Measurement measurementCopy = measurement; - measurementCopy.parameters()[boundLoc0] += ct.x_offset; - measurementCopy.parameters()[boundLoc1] += ct.y_offset; - measurementCopy.covariance()(boundLoc0, boundLoc0) *= ct.x_scale; - measurementCopy.covariance()(boundLoc1, boundLoc1) *= ct.y_scale; - Acts::visit_measurement(measurement.size(), [&](auto N) -> void { constexpr std::size_t kMeasurementSize = decltype(N)::value; + const ConstFixedBoundMeasurementProxy fixedMeasurement = + measurement; + + Acts::ActsVector calibratedParameters = + fixedMeasurement.parameters(); + Acts::ActsSquareMatrix calibratedCovariance = + fixedMeasurement.covariance(); + + calibratedParameters[boundLoc0] += ct.x_offset; + calibratedParameters[boundLoc1] += ct.y_offset; + calibratedCovariance(boundLoc0, boundLoc0) *= ct.x_scale; + calibratedCovariance(boundLoc1, boundLoc1) *= ct.y_scale; trackState.allocateCalibrated(kMeasurementSize); - trackState.calibrated() = - measurementCopy.parameters(); - trackState.calibratedCovariance() = - measurementCopy.covariance(); - trackState.setSubspaceIndices( - measurementCopy.subspaceIndices()); + trackState.calibrated() = calibratedParameters; + trackState.calibratedCovariance() = calibratedCovariance; + trackState.setSubspaceIndices(fixedMeasurement.subspaceIndices()); }); } diff --git a/Examples/Io/Csv/src/CsvMeasurementReader.cpp b/Examples/Io/Csv/src/CsvMeasurementReader.cpp index e1c31d52b63..ee036ea86a9 100644 --- a/Examples/Io/Csv/src/CsvMeasurementReader.cpp +++ b/Examples/Io/Csv/src/CsvMeasurementReader.cpp @@ -193,11 +193,14 @@ ActsExamples::ProcessCode ActsExamples::CsvMeasurementReader::read( readMeasurementsByGeometryId(m_cfg.inputDir, ctx.eventNumber); // Prepare containers for the hit data using the framework event data types - GeometryIdMultimap orderedMeasurements; + MeasurementContainer tmpMeasurements; + GeometryIdMultimap orderedMeasurements; IndexMultimap measurementSimHitsMap; IndexSourceLinkContainer sourceLinks; // need list here for stable addresses std::list sourceLinkStorage; + + tmpMeasurements.reserve(measurementData.size()); orderedMeasurements.reserve(measurementData.size()); // Safe long as we have single particle to sim hit association measurementSimHitsMap.reserve(measurementData.size()); @@ -251,14 +254,15 @@ ActsExamples::ProcessCode ActsExamples::CsvMeasurementReader::read( // the measurement will be stored is known before adding it. const Index index = orderedMeasurements.size(); IndexSourceLink& sourceLink = sourceLinkStorage.emplace_back(geoId, index); - auto measurement = createMeasurement(dParameters, sourceLink); + auto measurement = + createMeasurement(tmpMeasurements, dParameters, sourceLink); // Due to the previous sorting of the raw hit data by geometry id, new // measurements should always end up at the end of the container. previous // elements were not touched; cluster indices remain stable and can // be used to identify the m. - auto inserted = orderedMeasurements.emplace_hint( - orderedMeasurements.end(), geoId, std::move(measurement)); + auto inserted = orderedMeasurements.emplace_hint(orderedMeasurements.end(), + geoId, measurement); if (std::next(inserted) != orderedMeasurements.end()) { ACTS_FATAL("Something went horribly wrong with the hit sorting"); return ProcessCode::ABORT; @@ -269,7 +273,8 @@ ActsExamples::ProcessCode ActsExamples::CsvMeasurementReader::read( MeasurementContainer measurements; for (auto& [_, meas] : orderedMeasurements) { - measurements.emplace_back(std::move(meas)); + auto measurement = measurements.makeMeasurement(meas.size()); + measurement.copyFrom(meas); } // Generate measurement-particles-map diff --git a/Examples/Io/Csv/src/CsvMeasurementWriter.cpp b/Examples/Io/Csv/src/CsvMeasurementWriter.cpp index 0f65fca0d20..f31c812ba46 100644 --- a/Examples/Io/Csv/src/CsvMeasurementWriter.cpp +++ b/Examples/Io/Csv/src/CsvMeasurementWriter.cpp @@ -14,6 +14,7 @@ #include "ActsExamples/EventData/Cluster.hpp" #include "ActsExamples/EventData/Index.hpp" #include "ActsExamples/EventData/IndexSourceLink.hpp" +#include "ActsExamples/EventData/Measurement.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" #include "ActsExamples/Io/Csv/CsvInputOutput.hpp" #include "ActsExamples/Utilities/Paths.hpp" @@ -92,7 +93,8 @@ ActsExamples::ProcessCode ActsExamples::CsvMeasurementWriter::writeT( << " measurements in this event."); for (Index measIdx = 0u; measIdx < measurements.size(); ++measIdx) { - const auto& measurement = measurements[measIdx]; + const ConstVariableBoundMeasurementProxy measurement = + measurements.getMeasurement(measIdx); auto simHitIndices = makeRange(measurementSimHitsMap.equal_range(measIdx)); for (auto [_, simHitIdx] : simHitIndices) { diff --git a/Examples/Io/EDM4hep/include/ActsExamples/Io/EDM4hep/EDM4hepUtil.hpp b/Examples/Io/EDM4hep/include/ActsExamples/Io/EDM4hep/EDM4hepUtil.hpp index 432f5a28323..6e6bac7a154 100644 --- a/Examples/Io/EDM4hep/include/ActsExamples/Io/EDM4hep/EDM4hepUtil.hpp +++ b/Examples/Io/EDM4hep/include/ActsExamples/Io/EDM4hep/EDM4hepUtil.hpp @@ -91,10 +91,10 @@ void writeSimHit(const ActsFatras::Hit& from, edm4hep::MutableSimTrackerHit to, /// Known issues: /// - cluster channels are read from inappropriate fields /// - local 2D coordinates and time are read from position -Measurement readMeasurement(const edm4hep::TrackerHitPlane& from, - const edm4hep::TrackerHitCollection* fromClusters, - Cluster* toCluster, - const MapGeometryIdFrom& geometryMapper); +VariableBoundMeasurementProxy readMeasurement( + MeasurementContainer& container, const edm4hep::TrackerHitPlane& from, + const edm4hep::TrackerHitCollection* fromClusters, Cluster* toCluster, + const MapGeometryIdFrom& geometryMapper); /// Writes a measurement cluster to EDM4hep. /// @@ -106,7 +106,7 @@ Measurement readMeasurement(const edm4hep::TrackerHitPlane& from, /// Known issues: /// - cluster channels are written to inappropriate fields /// - local 2D coordinates and time are written to position -void writeMeasurement(const Measurement& from, +void writeMeasurement(const ConstVariableBoundMeasurementProxy& from, edm4hep::MutableTrackerHitPlane to, const Cluster* fromCluster, edm4hep::TrackerHitCollection& toClusters, diff --git a/Examples/Io/EDM4hep/src/EDM4hepMeasurementReader.cpp b/Examples/Io/EDM4hep/src/EDM4hepMeasurementReader.cpp index f24e64ccd8e..19606206e0e 100644 --- a/Examples/Io/EDM4hep/src/EDM4hepMeasurementReader.cpp +++ b/Examples/Io/EDM4hep/src/EDM4hepMeasurementReader.cpp @@ -66,11 +66,10 @@ ProcessCode EDM4hepMeasurementReader::read(const AlgorithmContext& ctx) { for (const auto& trackerHitPlane : trackerHitPlaneCollection) { Cluster cluster; - auto measurement = EDM4hepUtil::readMeasurement( - trackerHitPlane, &trackerHitRawCollection, &cluster, + EDM4hepUtil::readMeasurement( + measurements, trackerHitPlane, &trackerHitRawCollection, &cluster, [](std::uint64_t cellId) { return Acts::GeometryIdentifier(cellId); }); - measurements.push_back(std::move(measurement)); clusters.push_back(std::move(cluster)); } diff --git a/Examples/Io/EDM4hep/src/EDM4hepMeasurementWriter.cpp b/Examples/Io/EDM4hep/src/EDM4hepMeasurementWriter.cpp index 6b26db80362..f9b35e7edb1 100644 --- a/Examples/Io/EDM4hep/src/EDM4hepMeasurementWriter.cpp +++ b/Examples/Io/EDM4hep/src/EDM4hepMeasurementWriter.cpp @@ -55,7 +55,8 @@ ActsExamples::ProcessCode EDM4hepMeasurementWriter::writeT( << " measurements in this event."); for (Index hitIdx = 0u; hitIdx < measurements.size(); ++hitIdx) { - const auto& from = measurements[hitIdx]; + ConstVariableBoundMeasurementProxy from = + measurements.getMeasurement(hitIdx); const Cluster* fromCluster = clusters.empty() ? nullptr : &clusters[hitIdx]; auto to = hitsPlane.create(); diff --git a/Examples/Io/EDM4hep/src/EDM4hepUtil.cpp b/Examples/Io/EDM4hep/src/EDM4hepUtil.cpp index 6a7adfe98c5..dc863b135ab 100644 --- a/Examples/Io/EDM4hep/src/EDM4hepUtil.cpp +++ b/Examples/Io/EDM4hep/src/EDM4hepUtil.cpp @@ -18,6 +18,7 @@ #include "ActsExamples/Digitization/MeasurementCreation.hpp" #include "ActsExamples/EventData/Index.hpp" #include "ActsExamples/EventData/IndexSourceLink.hpp" +#include "ActsExamples/EventData/Measurement.hpp" #include "ActsExamples/EventData/SimHit.hpp" #include "ActsExamples/Validation/TrackClassification.hpp" @@ -144,8 +145,8 @@ void EDM4hepUtil::writeSimHit(const ActsFatras::Hit& from, to.setEDep(-delta4[Acts::eEnergy] / Acts::UnitConstants::GeV); } -Measurement EDM4hepUtil::readMeasurement( - const edm4hep::TrackerHitPlane& from, +VariableBoundMeasurementProxy EDM4hepUtil::readMeasurement( + MeasurementContainer& container, const edm4hep::TrackerHitPlane& from, const edm4hep::TrackerHitCollection* fromClusters, Cluster* toCluster, const MapGeometryIdFrom& geometryMapper) { // no need for digitization as we only want to identify the sensor @@ -172,7 +173,7 @@ Measurement EDM4hepUtil::readMeasurement( dParameters.values.push_back(pos.z); dParameters.variances.push_back(cov[5]); - auto to = createMeasurement(dParameters, sourceLink); + auto to = createMeasurement(container, dParameters, sourceLink); if (fromClusters != nullptr) { for (const auto objectId : from.getRawHits()) { @@ -196,11 +197,11 @@ Measurement EDM4hepUtil::readMeasurement( return to; } -void EDM4hepUtil::writeMeasurement(const Measurement& from, - edm4hep::MutableTrackerHitPlane to, - const Cluster* fromCluster, - edm4hep::TrackerHitCollection& toClusters, - const MapGeometryIdTo& geometryMapper) { +void EDM4hepUtil::writeMeasurement( + const ConstVariableBoundMeasurementProxy& from, + edm4hep::MutableTrackerHitPlane to, const Cluster* fromCluster, + edm4hep::TrackerHitCollection& toClusters, + const MapGeometryIdTo& geometryMapper) { Acts::GeometryIdentifier geoId = from.sourceLink().template get().geometryId(); diff --git a/Examples/Io/Root/src/RootAthenaDumpReader.cpp b/Examples/Io/Root/src/RootAthenaDumpReader.cpp index 8300237ef9e..001a8d90bdb 100644 --- a/Examples/Io/Root/src/RootAthenaDumpReader.cpp +++ b/Examples/Io/Root/src/RootAthenaDumpReader.cpp @@ -372,7 +372,7 @@ ActsExamples::ProcessCode ActsExamples::RootAthenaDumpReader::read( IndexSourceLink sl(Acts::GeometryIdentifier{CLmoduleID[im]}, im); - measurements.push_back(createMeasurement(digiPars, sl)); + createMeasurement(measurements, digiPars, sl); // Create measurement particles map and particles container for (const auto& [subevt, bc] : Acts::zip(CLparticleLink_eventIndex->at(im), diff --git a/Examples/Io/Root/src/RootMeasurementWriter.cpp b/Examples/Io/Root/src/RootMeasurementWriter.cpp index 6dc10e3b4b1..88b66e192f0 100644 --- a/Examples/Io/Root/src/RootMeasurementWriter.cpp +++ b/Examples/Io/Root/src/RootMeasurementWriter.cpp @@ -13,6 +13,7 @@ #include "ActsExamples/EventData/AverageSimHits.hpp" #include "ActsExamples/EventData/Index.hpp" #include "ActsExamples/EventData/IndexSourceLink.hpp" +#include "ActsExamples/EventData/Measurement.hpp" #include "ActsExamples/Framework/AlgorithmContext.hpp" #include "ActsExamples/Utilities/Range.hpp" @@ -152,9 +153,9 @@ struct RootMeasurementWriter::DigitizationTree { /// Convenience function to fill bound parameters /// /// @param m The measurement - void fillBoundMeasurement(const Measurement& m) { + void fillBoundMeasurement(const ConstVariableBoundMeasurementProxy& m) { for (unsigned int i = 0; i < m.size(); ++i) { - auto ib = m.subspaceIndices()[i]; + auto ib = m.subspaceIndexVector()[i]; recBound[ib] = m.parameters()[i]; varBound[ib] = m.covariance()(i, i); @@ -266,7 +267,8 @@ ProcessCode RootMeasurementWriter::writeT( std::lock_guard lock(m_writeMutex); for (Index hitIdx = 0u; hitIdx < measurements.size(); ++hitIdx) { - const auto& meas = measurements[hitIdx]; + const ConstVariableBoundMeasurementProxy meas = + measurements.getMeasurement(hitIdx); Acts::GeometryIdentifier geoId = meas.sourceLink().template get().geometryId(); diff --git a/Tests/UnitTests/Examples/EventData/MeasurementTests.cpp b/Tests/UnitTests/Examples/EventData/MeasurementTests.cpp index bab0b16e9e9..0156e01f03e 100644 --- a/Tests/UnitTests/Examples/EventData/MeasurementTests.cpp +++ b/Tests/UnitTests/Examples/EventData/MeasurementTests.cpp @@ -50,16 +50,19 @@ std::default_random_engine rng(123); BOOST_AUTO_TEST_SUITE(EventDataMeasurement) BOOST_DATA_TEST_CASE(VariableBoundOne, bd::make(boundIndices), index) { + MeasurementContainer container; + auto [params, cov] = generateParametersCovariance(rng); - auto meas = makeVariableSizeMeasurement(source, params, cov, index); + + FixedBoundMeasurementProxy<1> meas = container.makeMeasurement<1>(); + meas.setSourceLink(source); + meas.setSubspaceIndices(std::array{index}); + meas.parameters() = params; + meas.covariance() = cov; BOOST_CHECK_EQUAL(meas.size(), 1); for (auto i : boundIndices) { - if (i == index) { - BOOST_CHECK(meas.contains(i)); - } else { - BOOST_CHECK(!meas.contains(i)); - } + BOOST_CHECK_EQUAL(meas.contains(i), i == index); } BOOST_CHECK_EQUAL(meas.parameters(), params); BOOST_CHECK_EQUAL(meas.covariance(), cov); @@ -68,10 +71,17 @@ BOOST_DATA_TEST_CASE(VariableBoundOne, bd::make(boundIndices), index) { } BOOST_AUTO_TEST_CASE(VariableBoundAll) { + MeasurementContainer container; + auto [params, cov] = generateBoundParametersCovariance(rng); - auto meas = makeVariableSizeMeasurement(source, params, cov, eBoundLoc0, - eBoundLoc1, eBoundPhi, eBoundTheta, - eBoundQOverP, eBoundTime); + + FixedBoundMeasurementProxy meas = + container.makeMeasurement(); + meas.setSourceLink(source); + meas.setSubspaceIndices(std::array{eBoundLoc0, eBoundLoc1, eBoundTime, + eBoundPhi, eBoundTheta, eBoundQOverP}); + meas.parameters() = params; + meas.covariance() = cov; BOOST_CHECK_EQUAL(meas.size(), eBoundSize); for (auto i : boundIndices) { @@ -83,22 +93,35 @@ BOOST_AUTO_TEST_CASE(VariableBoundAll) { } BOOST_AUTO_TEST_CASE(VariableBoundReassign) { - // generate w/ a single parameter - auto [par1, cov1] = generateParametersCovariance(rng); - auto meas = makeVariableSizeMeasurement(source, par1, cov1, eBoundTheta); - BOOST_CHECK_EQUAL(meas.size(), 1); + MeasurementContainer container; + + // generate w/ two parameter + auto [params1, cov1] = generateParametersCovariance(rng); + + VariableBoundMeasurementProxy meas = container.makeMeasurement(2); + meas.setSourceLink(source); + meas.setSubspaceIndices(std::array{eBoundPhi, eBoundTheta}); + meas.parameters() = params1; + meas.covariance() = cov1; + + BOOST_CHECK_EQUAL(meas.size(), 2); BOOST_CHECK(!meas.contains(eBoundLoc0)); BOOST_CHECK(!meas.contains(eBoundLoc1)); BOOST_CHECK(!meas.contains(eBoundTime)); - BOOST_CHECK(!meas.contains(eBoundPhi)); + BOOST_CHECK(meas.contains(eBoundPhi)); BOOST_CHECK(meas.contains(eBoundTheta)); BOOST_CHECK(!meas.contains(eBoundQOverP)); // reassign w/ all parameters - auto [parN, covN] = generateBoundParametersCovariance(rng); - meas = makeVariableSizeMeasurement(source, parN, covN, eBoundLoc0, eBoundLoc1, - eBoundPhi, eBoundTheta, eBoundQOverP, - eBoundTime); + auto [paramsN, covN] = generateBoundParametersCovariance(rng); + + meas = container.makeMeasurement(eBoundSize); + meas.setSourceLink(source); + meas.setSubspaceIndices(std::array{eBoundLoc0, eBoundLoc1, eBoundTime, + eBoundPhi, eBoundTheta, eBoundQOverP}); + meas.parameters() = paramsN; + meas.covariance() = covN; + BOOST_CHECK_EQUAL(meas.size(), eBoundSize); BOOST_CHECK(meas.contains(eBoundLoc0)); BOOST_CHECK(meas.contains(eBoundLoc1)); diff --git a/Tests/UnitTests/Examples/Io/Csv/MeasurementReaderWriterTests.cpp b/Tests/UnitTests/Examples/Io/Csv/MeasurementReaderWriterTests.cpp index 4b4b6d78bbe..7fa64dcb128 100644 --- a/Tests/UnitTests/Examples/Io/Csv/MeasurementReaderWriterTests.cpp +++ b/Tests/UnitTests/Examples/Io/Csv/MeasurementReaderWriterTests.cpp @@ -50,11 +50,11 @@ BOOST_AUTO_TEST_CASE(CsvMeasurementRoundTrip) { Acts::Vector2 p = Acts::Vector2::Random(); Acts::SquareMatrix2 c = Acts::SquareMatrix2::Random(); - BoundVariableMeasurement m(Acts::SourceLink{sl}, - std::array{Acts::eBoundLoc0, Acts::eBoundLoc1}, - p, c); - - measOriginal.push_back(m); + FixedBoundMeasurementProxy<2> m = measOriginal.makeMeasurement<2>(); + m.setSourceLink(Acts::SourceLink(sl)); + m.setSubspaceIndices(std::array{Acts::eBoundLoc0, Acts::eBoundLoc1}); + m.parameters() = p; + m.covariance() = c; ActsExamples::Cluster cl;