Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Plugins/EDM4hep/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ podio_add_datamodel_core_lib(ActsPodioEdm "${headers}" "${sources}"
OUTPUT_FOLDER ${_output_folder}
)
target_link_libraries(ActsPodioEdm PUBLIC EDM4HEP::edm4hep)
target_include_directories(
ActsPodioEdm
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)

add_library(Acts::PodioEdm ALIAS ActsPodioEdm)

Expand All @@ -72,6 +78,11 @@ install(
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ActsPodioEdm
)

install(
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ActsPodioEdm/detail
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ActsPodioEdm
)

set(install_package_config_dir "${CMAKE_INSTALL_LIBDIR}/cmake/Acts")
install(EXPORT ActsPodioEdmTargets DESTINATION ${install_package_config_dir})

Expand Down
182 changes: 178 additions & 4 deletions Plugins/EDM4hep/edm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,189 @@ datatypes:
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
# 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)
Comment thread
paulgessinger marked this conversation as resolved.
- 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)
Comment thread
paulgessinger marked this conversation as resolved.

VectorMembers:
- float measurement // Entries in the measurement value vector
- float covariance // Entries in the measurement covariance vector. Order is column major

ExtraCode:
includes: "#include <ActsPodioEdm/detail/SubspaceIndexHelpers.hpp>"
declaration: |
/// Number of active subspace dimensions
/// @return The number of active subspace dimensions
std::size_t getSize() const {
return getSubspaceIndices().size();
}
Comment thread
paulgessinger marked this conversation as resolved.


/// 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<std::uint8_t> 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 <typename E> requires std::is_enum_v<E>
std::size_t findSubspaceIndex(E enumVal) const {
const auto indices = getSubspaceIndices();
return ActsPodioEdm::detail::findSubspaceIndex(
std::span<const std::uint8_t>{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 <typename E> requires std::is_enum_v<E>
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 <typename E> requires std::is_enum_v<E>
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 <ActsPodioEdm/detail/SubspaceIndexHelpers.hpp>"
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<const std::uint8_t> 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 <typename E> requires std::is_enum_v<E>
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 <typename E> requires std::is_enum_v<E>
void setCov(float val, E enumI, E enumJ) {
setCov(val, findSubspaceIndex(enumI), findSubspaceIndex(enumJ));
}
21 changes: 7 additions & 14 deletions Plugins/EDM4hep/include/ActsPlugins/EDM4hep/EDM4hepUtil.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
#include <span>
#include <stdexcept>

#include <boost/container/static_vector.hpp>
#include <edm4hep/MCParticle.h>
#include <edm4hep/MutableSimTrackerHit.h>
#include <edm4hep/MutableTrack.h>
Expand Down Expand Up @@ -339,13 +338,6 @@ constexpr bool kEdm4hepVertexHasTime =

void writeVertex(const Acts::Vertex& vertex, edm4hep::MutableVertex to);

namespace detail {
// These functions are exposed here so they can be used from the unit tests
std::uint32_t encodeIndices(std::span<const std::uint8_t> indices);
boost::container::static_vector<Acts::SubspaceIndex, Acts::eBoundSize>
decodeIndices(std::uint32_t type);
} // namespace detail

/// Write a measurement to an EDM4hep tracker hit
///
/// This function converts an ACTS measurement into the EDM4hep format. It
Expand All @@ -354,12 +346,14 @@ decodeIndices(std::uint32_t type);
/// - Time storage (in ns)
/// - Measurement values and covariance matrix storage
/// - Encoding of measurement indices into a 32-bit integer:
/// - First 4 bits: number of indices (max 6)
/// - Next 4 bits per index: which parameter is being measured (0-6)
/// - First 4 bits: number of indices (max
/// `ActsPodioEdm::detail::kMaxSubspaceSize`)
/// - Next 4 bits per index: measured bound parameter index (max
/// `ActsPodioEdm::detail::kMaxSubspaceIndex`)
///
/// The function will throw if:
/// - The number of indices exceeds 6
/// - Any index is larger than 6
/// - The number of indices exceeds `ActsPodioEdm::detail::kMaxSubspaceSize`
/// - Any index is larger than `ActsPodioEdm::detail::kMaxSubspaceIndex`
/// - There's a size mismatch between parameters and covariance matrix
///
/// @param gctx The geometry context
Expand All @@ -383,8 +377,7 @@ struct MeasurementData {
/// Covariance matrix of the measurement (full bound space)
Acts::BoundMatrix covariance{Acts::BoundMatrix::Zero()};
/// Indices of the measured parameters (subspace)
boost::container::static_vector<Acts::SubspaceIndex, Acts::eBoundSize>
indices;
std::vector<Acts::SubspaceIndex> indices;
/// Cell ID of the measurement
std::uint64_t cellId{0};
};
Expand Down
121 changes: 121 additions & 0 deletions Plugins/EDM4hep/include/ActsPodioEdm/detail/SubspaceIndexHelpers.hpp
Original file line number Diff line number Diff line change
@@ -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 <cstddef>
#include <cstdint>
#include <format>
#include <span>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <vector>

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;
Comment thread
paulgessinger marked this conversation as resolved.

/// 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<const std::uint8_t> indices) {
Comment thread
paulgessinger marked this conversation as resolved.
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<std::int32_t>(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<SubspaceIndex> decodeIndices(std::int32_t type) {
std::vector<SubspaceIndex> 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 <typename E>
requires std::is_enum_v<E>
inline std::size_t findSubspaceIndex(std::span<const SubspaceIndex> indices,
E enumVal) {
const auto target = static_cast<SubspaceIndex>(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<int>(enumVal)));
}

} // namespace ActsPodioEdm::detail
Loading
Loading