From 9ac279be95c87ac3ce5754f78d97c0bf3651636d Mon Sep 17 00:00:00 2001 From: Paul Gessinger Date: Wed, 5 Mar 2025 17:04:03 +0100 Subject: [PATCH 1/4] Add basic version of sensor-local tracker hit --- edm4hep.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/edm4hep.yaml b/edm4hep.yaml index d8cc96c67..61eaddcf1 100644 --- a/edm4hep.yaml +++ b/edm4hep.yaml @@ -481,6 +481,22 @@ datatypes: /// Set the position covariance matrix value for the two passed dimensions void setCovMatrix(float value, edm4hep::Cartesian dimI, edm4hep::Cartesian dimJ) { getCovMatrix().setValue(value, dimI, dimJ); } + edm4hep::TrackerHitLocal: + Description: "Sensor-local tracker hit" + Author: "EDM4hep authors" + Members: + - uint64_t cellID // ID of the sensor that created this hit + - int32_t type // type of raw data hit, use depends on writer + - int32_t quality // quality bit flag of the hit + - float time [ns] // time of the hit (depends on measurement tupe) + - float eDep [GeV] // energy deposited on the hit (optional) + - float eDepError [GeV] // error measured on EDep (optional) + - edm4hep::Vector3d position [mm] // global hit position (depends on measurement type) + + VectorMembers: + - float measurement // Entries in the measurement value vector + - float covariance // Entries in the measurement covariance vector. Order is column major + edm4hep::RawTimeSeries: Description: "Raw data of a detector readout" Author: "EDM4hep authors" @@ -680,6 +696,7 @@ interfaces: - edm4hep::TrackerHit3D - edm4hep::TrackerHitPlane - edm4hep::SenseWireHit + - edm4hep::TrackerHitLocal links: edm4hep::RecoMCParticleLink: From 6eeac8a3f762ce48b8dffdf64fa088e5bcc62d9f Mon Sep 17 00:00:00 2001 From: Paul Gessinger Date: Thu, 6 Mar 2025 11:29:08 +0100 Subject: [PATCH 2/4] Update edm4hep.yaml Co-authored-by: Mateusz Jakub Fila <37295697+m-fila@users.noreply.github.com> --- edm4hep.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/edm4hep.yaml b/edm4hep.yaml index 61eaddcf1..869cec4a6 100644 --- a/edm4hep.yaml +++ b/edm4hep.yaml @@ -488,7 +488,7 @@ datatypes: - uint64_t cellID // ID of the sensor that created this hit - int32_t type // type of raw data hit, use depends on writer - int32_t quality // quality bit flag of the hit - - float time [ns] // time of the hit (depends on measurement tupe) + - float time [ns] // time of the hit (depends on measurement type) - float eDep [GeV] // energy deposited on the hit (optional) - float eDepError [GeV] // error measured on EDep (optional) - edm4hep::Vector3d position [mm] // global hit position (depends on measurement type) From 5fc57f9c93d8e54d93fcbedfa54475dd10c449e5 Mon Sep 17 00:00:00 2001 From: Paul Gessinger Date: Mon, 8 Jun 2026 14:19:57 +0300 Subject: [PATCH 3/4] update to latest development version --- edm4hep.yaml | 183 +++++++++++++++++- .../edm4hep/utils/SubspaceIndexUtils.hpp | 121 ++++++++++++ 2 files changed, 301 insertions(+), 3 deletions(-) create mode 100644 utils/include/edm4hep/utils/SubspaceIndexUtils.hpp diff --git a/edm4hep.yaml b/edm4hep.yaml index 869cec4a6..b240d4e76 100644 --- a/edm4hep.yaml +++ b/edm4hep.yaml @@ -485,18 +485,195 @@ datatypes: Description: "Sensor-local tracker hit" Author: "EDM4hep authors" Members: + # These are chosen to be compatible with the `edm4hep::TrackerHit` interface + # (https://github.com/key4hep/EDM4hep/blob/c877c7fadf412db3c1126e7b410d8074a78014f2/edm4hep.yaml#L652-L666V) + # to allow for potential upstreaming. + # Members not used by ACTS (quality, eDep, eDepError) are omitted and + # fulfilled by throwing ExtraCode stubs to satisfy the interface. - uint64_t cellID // ID of the sensor that created this hit - int32_t type // type of raw data hit, use depends on writer - - int32_t quality // quality bit flag of the hit - float time [ns] // time of the hit (depends on measurement type) - - float eDep [GeV] // energy deposited on the hit (optional) - - float eDepError [GeV] // error measured on EDep (optional) - edm4hep::Vector3d position [mm] // global hit position (depends on measurement type) VectorMembers: - float measurement // Entries in the measurement value vector - float covariance // Entries in the measurement covariance vector. Order is column major + ExtraCode: + includes: "#include " + declaration: | + /// Number of active subspace dimensions + /// @return The number of active subspace dimensions + std::size_t getSize() const { + return getSubspaceIndices().size(); + } + + + /// Get the value for the passed subspace index + /// @param valueIndex The index of the value + /// @return The value + float getValue(std::size_t valueIndex) const { + const auto dim = getSize(); + auto values = getMeasurement(); + if (values.size() != dim) { + throw std::runtime_error("Measurement vector size mismatch"); + } + + if (valueIndex >= dim) { + throw std::runtime_error("Measurement index out of range"); + } + return values[valueIndex]; + } + + /// Get covariance value for the two passed matrix indices + /// @param indexI The first index + /// @param indexJ The second index + /// @return The covariance value + float getCov(std::size_t indexI, std::size_t indexJ) const { + auto cov = getCovariance(); + const auto dim = getSize(); + if (indexI >= dim || indexJ >= dim) { + throw std::runtime_error("Covariance index out of range"); + } + if (cov.size() != dim * dim) { + throw std::runtime_error("Covariance matrix size mismatch"); + } + const auto offset = indexJ * dim + indexI; + return cov[offset]; + } + + /// Decode and return the subspace indices stored in the type field + /// @return The subspace indices + std::vector getSubspaceIndices() const { + return ActsPodioEdm::detail::decodeIndices(getType()); + } + + /// Find the measurement-vector index for an enum-coded subspace coordinate + /// + /// @tparam E Enum type whose underlying value encodes a subspace index + /// @param enumVal The enum value to look up + /// @return The position in the measurement/covariance vector + /// @throws std::runtime_error if enumVal is not in the active subspace + template requires std::is_enum_v + std::size_t findSubspaceIndex(E enumVal) const { + const auto indices = getSubspaceIndices(); + return ActsPodioEdm::detail::findSubspaceIndex( + std::span{indices}, enumVal); + } + + /// Get measurement value for an enum-coded subspace coordinate + /// + /// Equivalent to getValue(findSubspaceIndex(enumVal)). + /// + /// @tparam E Enum type whose underlying value encodes a subspace index + /// @param enumVal The enum value identifying the coordinate + /// @return The measurement value + template requires std::is_enum_v + float getValue(E enumVal) const { + return getValue(findSubspaceIndex(enumVal)); + } + + /// Get covariance value for two enum-coded subspace coordinates + /// + /// Equivalent to getCov(findSubspaceIndex(enumI), findSubspaceIndex(enumJ)). + /// + /// @tparam E Enum type whose underlying value encodes a subspace index + /// @param enumI The first coordinate's enum value + /// @param enumJ The second coordinate's enum value + /// @return The covariance value at (enumI, enumJ) + template requires std::is_enum_v + float getCov(E enumI, E enumJ) const { + return getCov(findSubspaceIndex(enumI), findSubspaceIndex(enumJ)); + } + + // --- edm4hep::TrackerHit interface stubs (not implemented) --- + + /// @throws std::logic_error always — quality is not used in TrackerHitLocal + std::int32_t getQuality() const { + throw std::logic_error("getQuality() is not implemented in TrackerHitLocal"); + } + + /// @throws std::logic_error always — eDep is not used in TrackerHitLocal + float getEDep() const { + throw std::logic_error("getEDep() is not implemented in TrackerHitLocal"); + } + + /// @throws std::logic_error always — eDepError is not used in TrackerHitLocal + float getEDepError() const { + throw std::logic_error("getEDepError() is not implemented in TrackerHitLocal"); + } + + MutableExtraCode: + includes: "#include " + declaration: | + /// Set the value for the passed measurement-vector index + /// @param val The value to set + /// @param valueIndex The index of the value + void setValue(float val, std::size_t valueIndex) { + const auto dim = getSize(); + if (m_obj->m_measurement->size() != dim) { + throw std::runtime_error("Measurement vector not initialized - call setSubspaceIndices first"); + } + if (valueIndex >= dim) { + throw std::runtime_error("Measurement index out of range"); + } + (*m_obj->m_measurement)[valueIndex] = val; + } + + /// Set the covariance value for the two passed matrix indices + /// @param val The value to set + /// @param indexI The first index + /// @param indexJ The second index + void setCov(float val, std::size_t indexI, std::size_t indexJ) { + const auto dim = getSize(); + if (m_obj->m_covariance->size() != dim * dim) { + throw std::runtime_error("Covariance vector not initialized - call setSubspaceIndices first"); + } + if (indexI >= dim || indexJ >= dim) { + throw std::runtime_error("Covariance index out of range"); + } + const auto offset = indexJ * dim + indexI; + (*m_obj->m_covariance)[offset] = val; + } + + /// Encode and store subspace indices into the type field + /// @param indices The subspace indices + /// @note This will initialize the measurement and covariance vectors if they are not already initialized + void setSubspaceIndices(std::span indices) { + setType(ActsPodioEdm::detail::encodeIndices(indices)); + m_obj->m_measurement->assign(indices.size(), 0.f); + m_obj->m_covariance->assign(indices.size() * indices.size(), 0.f); + m_obj->data.measurement_begin = 0u; + m_obj->data.measurement_end = indices.size(); + m_obj->data.covariance_begin = 0u; + m_obj->data.covariance_end = indices.size() * indices.size(); + } + + /// Set measurement value for an enum-coded subspace coordinate + /// + /// Equivalent to setValue(val, findSubspaceIndex(enumVal)). + /// + /// @tparam E Enum type whose underlying value encodes a subspace index + /// @param val The value to set + /// @param enumVal The enum value identifying the coordinate + template requires std::is_enum_v + void setValue(float val, E enumVal) { + setValue(val, findSubspaceIndex(enumVal)); + } + + /// Set covariance value for two enum-coded subspace coordinates + /// + /// Equivalent to setCov(val, findSubspaceIndex(enumI), findSubspaceIndex(enumJ)). + /// + /// @tparam E Enum type whose underlying value encodes a subspace index + /// @param val The value to set + /// @param enumI The first coordinate's enum value + /// @param enumJ The second coordinate's enum value + template requires std::is_enum_v + void setCov(float val, E enumI, E enumJ) { + setCov(val, findSubspaceIndex(enumI), findSubspaceIndex(enumJ)); + } + edm4hep::RawTimeSeries: Description: "Raw data of a detector readout" Author: "EDM4hep authors" diff --git a/utils/include/edm4hep/utils/SubspaceIndexUtils.hpp b/utils/include/edm4hep/utils/SubspaceIndexUtils.hpp new file mode 100644 index 000000000..031d9feae --- /dev/null +++ b/utils/include/edm4hep/utils/SubspaceIndexUtils.hpp @@ -0,0 +1,121 @@ +// 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/. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ActsPodioEdm::detail { + +/// Encoded index type for local measurement subspace coordinates. +using SubspaceIndex = std::uint8_t; +/// Largest allowed local subspace index value. +constexpr std::uint8_t kMaxSubspaceIndex = 6u; +/// Maximum number of coordinates in an encoded local subspace. +constexpr std::size_t kMaxSubspaceSize = 6u; + +/// Encode a list of bound parameter indices into a 32-bit integer. +/// +/// This function bit-packs up to `kMaxSubspaceSize` parameter indices into a +/// single 32-bit unsigned integer for storage in EDM4hep format. +/// +/// Bit layout: +/// - Bits 0-3: Number of indices (size) +/// - Bits 4-7: First index +/// - Bits 8-11: Second index +/// - Bits 12-15: Third index +/// - (and so on, up to `kMaxSubspaceSize` indices total) +/// +/// @param indices Span of parameter indices to encode (max +/// `kMaxSubspaceSize` elements) +/// @return Packed 32-bit unsigned integer containing all indices +inline std::int32_t encodeIndices(std::span indices) { + if (indices.size() > kMaxSubspaceSize) { + throw std::runtime_error( + std::format("Number of indices exceeds maximum of {} for EDM4hep", + kMaxSubspaceSize)); + } + + std::int32_t result = 0; + std::uint8_t shift = 0; + result |= (indices.size() << 0); + shift += 4; + + for (std::uint8_t index : indices) { + if (index > kMaxSubspaceIndex) { + throw std::runtime_error(std::format( + "Index out of range: maximum allowed is {}", kMaxSubspaceIndex)); + } + result |= (static_cast(index) << shift); + shift += 4; + } + return result; +} + +/// Decode a 32-bit integer back into a list of bound parameter indices. +/// +/// This function unpacks a bit-packed integer (created by encodeIndices) back +/// into the original list of parameter indices. See encodeIndices for the bit +/// layout specification. +/// +/// @param type Packed 32-bit unsigned integer containing encoded indices +/// @return Vector of decoded parameter indices (each in +/// `[0, kMaxSubspaceIndex]`) +inline std::vector decodeIndices(std::int32_t type) { + std::vector result; + std::uint8_t size = type & 0xF; + if (size > kMaxSubspaceSize) { + throw std::runtime_error( + std::format("Number of indices exceeds maximum of {} for EDM4hep", + kMaxSubspaceSize)); + } + result.resize(size); + for (std::size_t i = 0; i < result.size(); ++i) { + result[i] = (type >> ((i + 1) * 4)) & 0xF; + if (result[i] > kMaxSubspaceIndex) { + throw std::runtime_error(std::format( + "Index out of range: maximum allowed is {}", kMaxSubspaceIndex)); + } + } + return result; +} + +/// Find the measurement-vector position of an enum-coded subspace coordinate. +/// +/// Searches @p indices for the given enum value (cast to SubspaceIndex) and +/// returns its position. This position is the index into the measurement and +/// covariance vectors stored in a TrackerHitLocal. +/// +/// @tparam E Enum type whose underlying value encodes a subspace index +/// @param indices Active subspace indices (e.g. from decodeIndices()) +/// @param enumVal The enum value to look up +/// @return Position of @p enumVal in @p indices +/// @throws std::runtime_error if @p enumVal is not present in @p indices +template + requires std::is_enum_v +inline std::size_t findSubspaceIndex(std::span indices, + E enumVal) { + const auto target = static_cast(enumVal); + for (std::size_t i = 0; i < indices.size(); ++i) { + if (indices[i] == target) { + return i; + } + } + throw std::runtime_error( + std::format("Enum value {} not found in subspace indices", + static_cast(enumVal))); +} + +} // namespace ActsPodioEdm::detail From 2b3ea1dfd91c93746f62a78e56178e2c01e6d091 Mon Sep 17 00:00:00 2001 From: Paul Gessinger Date: Mon, 8 Jun 2026 14:21:44 +0300 Subject: [PATCH 4/4] update to latest prototoype --- edm4hep.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/edm4hep.yaml b/edm4hep.yaml index b240d4e76..c58cd5179 100644 --- a/edm4hep.yaml +++ b/edm4hep.yaml @@ -485,11 +485,6 @@ datatypes: Description: "Sensor-local tracker hit" Author: "EDM4hep authors" Members: - # These are chosen to be compatible with the `edm4hep::TrackerHit` interface - # (https://github.com/key4hep/EDM4hep/blob/c877c7fadf412db3c1126e7b410d8074a78014f2/edm4hep.yaml#L652-L666V) - # to allow for potential upstreaming. - # Members not used by ACTS (quality, eDep, eDepError) are omitted and - # fulfilled by throwing ExtraCode stubs to satisfy the interface. - uint64_t cellID // ID of the sensor that created this hit - int32_t type // type of raw data hit, use depends on writer - float time [ns] // time of the hit (depends on measurement type)