diff --git a/edm4hep.yaml b/edm4hep.yaml index d8cc96c67..c58cd5179 100644 --- a/edm4hep.yaml +++ b/edm4hep.yaml @@ -481,6 +481,194 @@ 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 + - float time [ns] // time of the hit (depends on measurement type) + - 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" @@ -680,6 +868,7 @@ interfaces: - edm4hep::TrackerHit3D - edm4hep::TrackerHitPlane - edm4hep::SenseWireHit + - edm4hep::TrackerHitLocal links: edm4hep::RecoMCParticleLink: 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