Skip to content

EDM De-Algebraification #1, main branch (2026.04.08.)#1287

Open
krasznaa wants to merge 10 commits intoacts-project:mainfrom
krasznaa:EDMDeAlgebraification-main-20260401
Open

EDM De-Algebraification #1, main branch (2026.04.08.)#1287
krasznaa wants to merge 10 commits intoacts-project:mainfrom
krasznaa:EDMDeAlgebraification-main-20260401

Conversation

@krasznaa
Copy link
Copy Markdown
Member

@krasznaa krasznaa commented Apr 8, 2026

With this let me start yet another big rewrite / redesign. 🤔

It's been bugging me for a long time that the data model we use depends on the algebra that we use. Which in my mind is not a workable API. The data itself needs to be fixed somehow.

So I started by making traccc::edm::silicon_cell and traccc::edm::measurement not be dependent on the build setup of the project. As these seemed technically the easiest to do, and since edm::measurement is used pretty much everywhere, I thought that this would be a good stress-test for the rewrite.

Making edm::silicon_cell always use float values for its "activation" and "time" properties was a trivial change, that didn't actually necessitate any code changes. So that was surprisingly easy.

But of course edm::measurement was a bit more tricky. What we do currently is that we use the detray::point2D type for storing the local coordinates and the variances of those local coordinates. But I believe it's a lot better idea to just store plain std::array<float, 2> objects. Independent of what algebra we want to use for our calculations.

To help with this, I added a couple of additional functions to edm::measurement. Which would help with both retrieving and setting the local_position and local_variance variables using Detray objects directly. Just so that the actual algorithmic code would look a bit more "natural". Like:

    const point3 global = sf.local_to_global(
        gctx,
        meas.template local_position_in<typename detector_t::algebra_type>(),
        {});

(Okay, maybe "natural" is a bit over-selling it. 🤔)

I see this all as one step towards hiding the whole algebra business behind the scenes. As the API of the GPU tools should really not reveal what algebra is being used underneath. In case we end up using array and Eigen algebras interchangeably in the end after all. 🤔

I assume there will be plenty of discussion around this. Especially around what we'll do with edm::track_state afterwards. (As there I do have some worries about what we actually want to do.) But let's see how this goes...

@krasznaa krasznaa added the edm Changes to the data model label Apr 8, 2026
@krasznaa krasznaa force-pushed the EDMDeAlgebraification-main-20260401 branch from f0da9fb to de91c95 Compare April 8, 2026 10:53
Copy link
Copy Markdown
Member

@stephenswat stephenswat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the algebra from the EDM is largely uncontroversial, so I'm on board with this. The only real issue with this PR is that it tasks the EDM with the responsibility of type conversions where that should really be the callers' responsibility.

Comment on lines +44 to +46
template <typename SIZE_TYPE>
TRACCC_HOST_DEVICE constexpr subspace(
const std::array<SIZE_TYPE, kSize>& indices) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would we not just use the size_type that is already defined in the class?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

size_type in this class is actually algebra specific. For std::array it's std::size_t. For some other algebras it would be unsigned int.

And I'm here wondering that we're wasting a lot of memory on this. For now I went with unsigned int in edm::measurement. But even std::uint8_t should be enough I reckon. 🤔

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely yes, this could be a smaller integer type!

Comment on lines +196 to +207
/// Set the subspace of the measurement
///
/// Using a possibly slightly different array than the one used by the
/// object itself.
///
/// @note This function must only be used on proxy objects, not on
/// containers!
///
/// @param subs The subspace to set
///
template <std::integral TYPE>
TRACCC_HOST_DEVICE void set_subspace(const std::array<TYPE, 2u>& subs);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than templating this function on the size type of subspace, callers of this function should rather ignore the size type of their local algebra and simply use subspace::size_type.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole reason that algebras advertise their size_type is that we had issues with using std::size_t versus unsigned int with the various algebras. With compilers freaking out about type conversions.

Comment on lines +97 to +117
/// Get the local variance object in a specific (Detray) algebra
///
/// @note This function must only be used on proxy objects, not on
/// containers!
///
/// @tparam ALGEBRA_TYPE The algebra to retrieve the local variance in
/// @return An algebra specific 1D/2D point object
///
template <detray::concepts::algebra ALGEBRA_TYPE>
TRACCC_HOST_DEVICE detray::dpoint2D<ALGEBRA_TYPE> local_variance_in() const;
/// Set the local variance expressed in a specific (Detray) algebra
///
/// @note This function must only be used on proxy objects, not on
/// containers!
///
/// @tparam ALGEBRA_TYPE The algebra to set the local variance in
/// @param var The local variance to set
///
template <detray::concepts::algebra ALGEBRA_TYPE>
TRACCC_HOST_DEVICE void set_local_variance_in(
const detray::dpoint2D<ALGEBRA_TYPE>& var);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Embedding all of this conversion logic into this type is poor API design. It would be nicer to introduce a few free functions which can convert a detray::dpoint2D from any given algebra to a canonical standard type, and it should then be the responsibility of the call site to ensure that they produce a dpoint2D of the right type.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we can have a free-standing function that can convert between whatever dpoint2D and std::array<float, 2>. But I'm not quite as convinced as you that it's hurtful to have the EDM class know exactly what type it itself has. For me this seemed like a quite good place to put such a conversion in.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The free function approach avoids quite a lot of awkwardness at both the call site (no need to call a templated member function) and the EDM (no need to define separate getters and setters, no need to duplicate conversion code, no need to include the algebra in a template variable).

This EDM design has four functions for each dpoint2D member, where only two are really necessary (both of which are not templated):

    TRACCC_HOST_DEVICE
    auto& local_position() { return BASE::template get<0>(); }

    TRACCC_HOST_DEVICE
    const auto& local_position() const { return BASE::template get<0>(); }

    template <detray::concepts::algebra ALGEBRA_TYPE>
    TRACCC_HOST_DEVICE detray::dpoint2D<ALGEBRA_TYPE> local_position_in() const;

    template <detray::concepts::algebra ALGEBRA_TYPE>
    TRACCC_HOST_DEVICE void set_local_position_in(
        const detray::dpoint2D<ALGEBRA_TYPE>& pos);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious about your proposal. 😕 What exact arguments would those free-standing functions use?

If we want to make use of detray::dpoint2D, I don't think there's a way to avoid specifying explicitly which algebra we're using. As it's not possible to figure out purely from dpoint2D<T> what T should be. And I also would like to avoid using explicit Eigen, etc. types directly in the traccc code.

So, what did you have in mind exactly? 🤔

Copy link
Copy Markdown
Member

@stephenswat stephenswat Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm suggesting we could have the following free functions:

template<typename T>
std::array<float, 2u> to_canonical_point2d(const T & p) requires detray::concepts::point<T> {
    ...
}

template<typename Algebra>
detray::dpoint2D<Algebra> from_canonical_point2d(const std::array<float, 2u> & p) {
    ...
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there were some pre-existing helper functions in measurement_helpers.hpp, I added functions there in the same style as those already existing things. It did not make an amazing API though. 😦

Still, client code will not need to be exposed to this type of code...

Comment on lines +16 to +53
template <typename BASE>
template <detray::concepts::algebra ALGEBRA_TYPE>
TRACCC_HOST_DEVICE detray::dpoint2D<ALGEBRA_TYPE>
measurement<BASE>::local_position_in() const {

detray::dpoint2D<ALGEBRA_TYPE> result;
getter::element(result, 0) =
static_cast<typename ALGEBRA_TYPE::value_type>(local_position()[0]);
getter::element(result, 1) =
static_cast<typename ALGEBRA_TYPE::value_type>(local_position()[1]);
return result;
}

template <typename BASE>
template <detray::concepts::algebra ALGEBRA_TYPE>
TRACCC_HOST_DEVICE void measurement<BASE>::set_local_position_in(
const detray::dpoint2D<ALGEBRA_TYPE>& pos) {

local_position()[0] = static_cast<float>(getter::element(pos, 0));
local_position()[1] = static_cast<float>(getter::element(pos, 1));
}

template <typename BASE>
template <detray::concepts::algebra ALGEBRA_TYPE>
TRACCC_HOST_DEVICE detray::dpoint2D<ALGEBRA_TYPE>
measurement<BASE>::local_variance_in() const {

detray::dpoint2D<ALGEBRA_TYPE> result;
getter::element(result, 0) =
static_cast<typename ALGEBRA_TYPE::value_type>(local_variance()[0]);
getter::element(result, 1) =
static_cast<typename ALGEBRA_TYPE::value_type>(local_variance()[1]);
return result;
}

template <typename BASE>
template <detray::concepts::algebra ALGEBRA_TYPE>
TRACCC_HOST_DEVICE void measurement<BASE>::set_local_variance_in(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Case in point, this is all just duplicated code.

@krasznaa krasznaa force-pushed the EDMDeAlgebraification-main-20260401 branch from de91c95 to edcd9a6 Compare April 9, 2026 11:24
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Apr 9, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

edm Changes to the data model

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants