Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
103 changes: 103 additions & 0 deletions Plugins/EDM4hep/edm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,106 @@ datatypes:
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(
static_cast<std::uint32_t>(getType()));
}

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 == nullptr || m_obj->m_measurement->size() != dim) {
Comment thread
paulgessinger marked this conversation as resolved.
Outdated
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 == nullptr || 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(static_cast<std::int32_t>(
ActsPodioEdm::detail::encodeIndices(indices)));
if (m_obj->m_measurement == nullptr) {
m_obj->m_measurement = new std::vector<float>{};
}
if (m_obj->m_covariance == nullptr) {
m_obj->m_covariance = new std::vector<float>{};
}
Comment thread
paulgessinger marked this conversation as resolved.
Outdated
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();
}
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// 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 <span>
#include <stdexcept>
#include <string>
#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::uint32_t encodeIndices(std::span<const std::uint8_t> indices) {
Comment thread
paulgessinger marked this conversation as resolved.
Outdated
if (indices.size() > kMaxSubspaceSize) {
throw std::runtime_error("Number of indices exceeds maximum of " +
std::to_string(kMaxSubspaceSize) + " for EDM4hep");
}

std::uint32_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("Index out of range: maximum allowed is " +
std::to_string(kMaxSubspaceIndex));
}
result |= (static_cast<std::uint32_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::uint32_t type) {
std::vector<SubspaceIndex> result;
std::uint8_t size = type & 0xF;
if (size > kMaxSubspaceSize) {
throw std::runtime_error("Number of indices exceeds maximum of " +
std::to_string(kMaxSubspaceSize) + " for EDM4hep");
}
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("Index out of range: maximum allowed is " +
std::to_string(kMaxSubspaceIndex));
}
}
return result;
}

} // namespace ActsPodioEdm::detail
82 changes: 9 additions & 73 deletions Plugins/EDM4hep/src/EDM4hepUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,72 +294,6 @@ void writeVertex(const Vertex& vertex, edm4hep::MutableVertex to) {
writeVertex(vertex, to);
}

namespace detail {
/// Encode a list of bound parameter indices into a 32-bit integer.
///
/// This function bit-packs up to 6 parameter indices (each 0-5 corresponding to
/// eBoundLoc0, eBoundLoc1, eBoundPhi, eBoundTheta, eBoundQOverP, eBoundTime)
/// 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 6 indices total)
///
/// @param indices Span of parameter indices to encode (max 6 elements)
/// @return Packed 32-bit unsigned integer containing all indices
std::uint32_t encodeIndices(std::span<const std::uint8_t> indices) {
if (indices.size() > eBoundSize) {
throw std::runtime_error(
"Number of indices exceeds maximum of 6 for EDM4hep");
}
std::uint32_t result = 0;

std::uint8_t shift = 0;
result |= (indices.size() << 0);
shift += 4;

for (std::uint8_t index : indices) {
if (index > eBoundSize) {
throw std::runtime_error(
"Index out of range: can only encode indices up to 4 bits (0-15)");
}
result |= (static_cast<std::uint32_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 (0-5 for each bound parameter)
boost::container::static_vector<SubspaceIndex, eBoundSize> decodeIndices(
std::uint32_t type) {
boost::container::static_vector<SubspaceIndex, eBoundSize> result;
std::uint8_t size = type & 0xF;
if (size > eBoundSize) {
throw std::runtime_error(
"Number of indices exceeds maximum of 6 for EDM4hep");
}
result.resize(size);
for (std::size_t i = 0; i < result.size(); ++i) {
result[i] = (type >> ((i + 1) * 4)) & 0xF;
if (result[i] > eBoundSize) {
throw std::runtime_error(
"Index out of range: can only encode indices up to 4 bits (0-15)");
}
}
return result;
}
} // namespace detail

void writeMeasurement(const GeometryContext& gctx,
const Eigen::Map<const DynamicVector>& parameters,
const Eigen::Map<const DynamicMatrix>& covariance,
Expand All @@ -379,7 +313,7 @@ void writeMeasurement(const GeometryContext& gctx,
to.setCellID(cellId);
}

to.setType(detail::encodeIndices(indices));
to.setSubspaceIndices({indices.begin(), indices.end()});

auto loc0 = std::ranges::find(indices, eBoundLoc0);
auto loc1 = std::ranges::find(indices, eBoundLoc1);
Expand All @@ -399,17 +333,19 @@ void writeMeasurement(const GeometryContext& gctx,
static_cast<float>(parameters[timeOffset] / Acts::UnitConstants::ns));
}

for (double value : std::span{parameters.data(), dim}) {
to.addToMeasurement(static_cast<float>(value));
for (std::size_t i = 0; i < dim; ++i) {
to.setValue(static_cast<float>(parameters[i]), i);
}

for (double value : std::span{covariance.data(), dim * dim}) {
to.addToCovariance(static_cast<float>(value));
for (std::size_t i = 0; i < dim; ++i) {
for (std::size_t j = 0; j < dim; ++j) {
to.setCov(static_cast<float>(covariance(i, j)), i, j);
}
}
}

MeasurementData readMeasurement(const ActsPodioEdm::TrackerHitLocal& from) {
auto indices = detail::decodeIndices(from.getType());
auto indices = from.getSubspaceIndices();
auto meas = from.getMeasurement();
auto cov = from.getCovariance();

Expand All @@ -431,7 +367,7 @@ MeasurementData readMeasurement(const ActsPodioEdm::TrackerHitLocal& from) {
for (std::size_t i = 0; i < dim; ++i) {
for (std::size_t j = 0; j < dim; ++j) {
result.covariance(result.indices[i], result.indices[j]) =
cov[i * dim + j]; // row-major
from.getCov(i, j);
}
}

Expand Down
Loading
Loading