Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-15 10:18:20

0001 /*
0002  * Copyright (c) 2014-2024 Key4hep-Project.
0003  *
0004  * This file is part of Key4hep.
0005  * See https://key4hep.github.io/key4hep-doc/ for further info.
0006  *
0007  * Licensed under the Apache License, Version 2.0 (the "License");
0008  * you may not use this file except in compliance with the License.
0009  * You may obtain a copy of the License at
0010  *
0011  *     http://www.apache.org/licenses/LICENSE-2.0
0012  *
0013  * Unless required by applicable law or agreed to in writing, software
0014  * distributed under the License is distributed on an "AS IS" BASIS,
0015  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0016  * See the License for the specific language governing permissions and
0017  * limitations under the License.
0018  */
0019 #ifndef FWCORE_TRANSFORMER_H
0020 #define FWCORE_TRANSFORMER_H
0021 
0022 #include "Gaudi/Functional/details.h"
0023 #include "Gaudi/Functional/utilities.h"
0024 #include <GaudiKernel/FunctionalFilterDecision.h>
0025 
0026 #include "k4FWCore/FunctionalUtils.h"
0027 
0028 // #include "GaudiKernel/CommonMessaging.h"
0029 
0030 #include <ranges>
0031 #include <stdexcept>
0032 #include <type_traits>
0033 #include <utility>
0034 
0035 namespace k4FWCore {
0036 
0037 namespace details {
0038 
0039   template <typename Signature, typename Traits_>
0040   struct Transformer;
0041 
0042   template <typename Out, typename... In, typename Traits_>
0043   struct Transformer<Out(const In&...), Traits_>
0044       : Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_> {
0045     using Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_>::DataHandleMixin;
0046 
0047     static_assert(((std::is_base_of_v<podio::CollectionBase, In> || isVectorLike_v<In>)&&...),
0048                   "Transformer and Producer input types must be EDM4hep collections or vectors of collections");
0049     static_assert((std::is_base_of_v<podio::CollectionBase, Out> || isVectorLike_v<Out> ||
0050                    std::is_same_v<podio::CollectionBase*, Out>),
0051                   "Transformer and Producer output types must be EDM4hep collections or vectors of collections");
0052 
0053     template <typename T>
0054     using InputHandle_t = Gaudi::Functional::details::InputHandle_t<Traits_, std::remove_pointer_t<T>>;
0055     template <typename T>
0056     using OutputHandle_t = Gaudi::Functional::details::OutputHandle_t<Traits_, std::remove_pointer_t<T>>;
0057 
0058     std::tuple<std::vector<InputHandle_t<typename EventStoreType<In>::type>>...> m_inputs;
0059     std::tuple<std::vector<OutputHandle_t<typename EventStoreType<Out>::type>>> m_outputs;
0060     std::array<Gaudi::Property<std::vector<DataObjID>>, sizeof...(In)> m_inputLocations{};
0061     Gaudi::Property<std::vector<DataObjID>> m_outputLocations{};
0062 
0063     using base_class = Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_>;
0064 
0065     using KeyValues = typename base_class::KeyValues;
0066 
0067     template <typename IArgs, typename OArgs, std::size_t... I, std::size_t... J>
0068     Transformer(std::string name, ISvcLocator* locator, const IArgs& inputs, std::index_sequence<I...>,
0069                 const OArgs& outputs, std::index_sequence<J...>)
0070         : base_class(std::move(name), locator),
0071           // The input locations are filled by creating a property with a
0072           // callback function that creates the handles because when the
0073           // callback runs is when the input locations become available (from
0074           // a steering file, for example) and the handles have to be created
0075           // for Gaudi to know the data flow
0076           m_inputLocations{Gaudi::Property<std::vector<DataObjID>>{
0077               this, std::get<I>(inputs).first, to_DataObjID(std::get<I>(inputs).second),
0078               [this](Gaudi::Details::PropertyBase&) {
0079                 std::vector<InputHandle_t<typename EventStoreType<In>::type>> h;
0080                 for (auto& value : this->m_inputLocations[I].value()) {
0081                   auto handle = InputHandle_t<typename EventStoreType<In>::type>(value, this);
0082                   h.push_back(std::move(handle));
0083                 }
0084                 std::get<I>(m_inputs) = std::move(h);
0085               },
0086               Gaudi::Details::Property::ImmediatelyInvokeHandler{true}}...},
0087           // Same as above for the output locations
0088           m_outputLocations{Gaudi::Property<std::vector<DataObjID>>{
0089               this, std::get<J>(outputs).first, to_DataObjID(std::get<J>(outputs).second),
0090               [this](Gaudi::Details::PropertyBase&) {
0091                 std::vector<OutputHandle_t<typename EventStoreType<Out>::type>> h;
0092                 for (auto& inpID : this->m_outputLocations.value()) {
0093                   if (inpID.key().empty()) {
0094                     continue;
0095                   }
0096                   auto handle = OutputHandle_t<typename EventStoreType<Out>::type>(inpID, this);
0097                   h.push_back(std::move(handle));
0098                 }
0099                 std::get<0>(m_outputs) = std::move(h);
0100               },
0101               Gaudi::Details::Property::ImmediatelyInvokeHandler{true}}...} {}
0102 
0103     constexpr static std::size_t N_in = sizeof...(In);
0104     constexpr static std::size_t N_out = 1;
0105 
0106     Transformer(std::string name, ISvcLocator* locator,
0107                 Gaudi::Functional::details::RepeatValues_<KeyValues, N_in> const& inputs,
0108                 Gaudi::Functional::details::RepeatValues_<KeyValues, N_out> const& outputs)
0109         : Transformer(std::move(name), locator, inputs, std::index_sequence_for<In...>{}, outputs,
0110                       std::index_sequence_for<Out>{}) {}
0111 
0112     // derived classes are NOT allowed to implement execute ...
0113     StatusCode execute(const EventContext& ctx) const final {
0114       try {
0115         if constexpr (isVectorLike<Out>::value) {
0116           std::tuple<Out> tmp = filter_evtcontext_tt<In...>::apply(*this, ctx, this->m_inputs);
0117           putVectorOutputs<0, Out>(std::move(tmp), m_outputs, this);
0118         } else {
0119           Gaudi::Functional::details::put(
0120               std::get<0>(this->m_outputs)[0],
0121               convertToUniquePtr(std::move(filter_evtcontext_tt<In...>::apply(*this, ctx, this->m_inputs))));
0122         }
0123         return Gaudi::Functional::FilterDecision::PASSED;
0124       } catch (GaudiException& e) {
0125         (e.code() ? this->warning() : this->error()) << e.tag() << " : " << e.message() << endmsg;
0126         return e.code();
0127       }
0128     }
0129 
0130     /**
0131      * @brief    Get the input locations for a given input index
0132      * @param i  The index of the input
0133      * @return   A range of the input locations
0134      */
0135     auto inputLocations(size_t i) const {
0136       if (i >= sizeof...(In)) {
0137         throw std::out_of_range("Called inputLocations with an index out of range, index: " + std::to_string(i) +
0138                                 ", number of inputs: " + std::to_string(sizeof...(In)));
0139       }
0140       return m_inputLocations[i] | std::views::transform([](const DataObjID& id) -> const auto& { return id.key(); });
0141     }
0142     /**
0143      * @brief       Get the input locations for a given input name
0144      * @param name  The name of the input
0145      * @return      A range of the input locations
0146      */
0147     auto inputLocations(std::string_view name) const {
0148       auto it = std::ranges::find_if(m_inputLocations, [&name](const auto& prop) { return prop.name() == name; });
0149       if (it == m_inputLocations.end()) {
0150         throw std::runtime_error("Called inputLocations with an unknown name");
0151       }
0152       return it->value() | std::views::transform([](const DataObjID& id) -> const auto& { return id.key(); });
0153     }
0154 
0155     /**
0156      * @brief    Get the output locations
0157      * @return   A range of the output locations
0158      */
0159     auto outputLocations() const {
0160       return m_outputLocations | std::views::transform([](const DataObjID& id) -> const auto& { return id.key(); });
0161     }
0162     /**
0163      * @brief       Get the output locations for a given output name
0164      * @param name  The name of the output
0165      * @return      A range of the output locations
0166      */
0167     auto outputLocations(std::string_view name) const {
0168       if (name != m_outputLocations.name()) {
0169         throw std::runtime_error("Called outputLocations with an unknown name");
0170       }
0171       return m_outputLocations | std::views::transform([](const DataObjID& id) -> const auto& { return id.key(); });
0172     }
0173     static constexpr std::size_t inputLocationsSize() { return sizeof...(In); }
0174 
0175     // ... instead, they must implement the following operator
0176     virtual Out operator()(const In&...) const = 0;
0177   };
0178 
0179   template <typename Signature, typename Traits_>
0180   struct MultiTransformer;
0181 
0182   template <typename... Out, typename... In, typename Traits_>
0183   struct MultiTransformer<std::tuple<Out...>(const In&...), Traits_>
0184       : Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_> {
0185     using Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_>::DataHandleMixin;
0186 
0187     static_assert(((std::is_base_of_v<podio::CollectionBase, In> || isVectorLike<In>::value) && ...),
0188                   "Transformer and Producer input types must be EDM4hep collections or vectors of collections");
0189     static_assert(((std::is_base_of_v<podio::CollectionBase, Out> || isVectorLike<Out>::value) && ...),
0190                   "Transformer and Producer output types must be EDM4hep collections or vectors of collections");
0191 
0192     template <typename T>
0193     using InputHandle_t = Gaudi::Functional::details::InputHandle_t<Traits_, std::remove_pointer_t<T>>;
0194     template <typename T>
0195     using OutputHandle_t = Gaudi::Functional::details::OutputHandle_t<Traits_, std::remove_pointer_t<T>>;
0196 
0197     std::tuple<std::vector<InputHandle_t<typename EventStoreType<In>::type>>...> m_inputs;
0198     std::tuple<std::vector<OutputHandle_t<typename EventStoreType<Out>::type>>...> m_outputs;
0199     std::array<Gaudi::Property<std::vector<DataObjID>>, sizeof...(In)> m_inputLocations{};
0200     std::array<Gaudi::Property<std::vector<DataObjID>>, sizeof...(Out)> m_outputLocations{};
0201 
0202     using base_class = Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_>;
0203 
0204     using KeyValues = typename base_class::KeyValues;
0205 
0206     template <typename IArgs, typename OArgs, std::size_t... I, std::size_t... J>
0207     MultiTransformer(std::string name, ISvcLocator* locator, const IArgs& inputs, std::index_sequence<I...>,
0208                      const OArgs& outputs, std::index_sequence<J...>)
0209         : base_class(std::move(name), locator),
0210           m_inputLocations{Gaudi::Property<std::vector<DataObjID>>{
0211               this, std::get<I>(inputs).first, to_DataObjID(std::get<I>(inputs).second),
0212               [this](Gaudi::Details::PropertyBase&) {
0213                 std::vector<InputHandle_t<typename EventStoreType<In>::type>> h;
0214                 for (auto& value : this->m_inputLocations[I].value()) {
0215                   auto handle = InputHandle_t<typename EventStoreType<In>::type>(value, this);
0216                   h.push_back(std::move(handle));
0217                 }
0218                 std::get<I>(m_inputs) = std::move(h);
0219               },
0220               Gaudi::Details::Property::ImmediatelyInvokeHandler{true}}...},
0221           m_outputLocations{Gaudi::Property<std::vector<DataObjID>>{
0222               this, std::get<J>(outputs).first, to_DataObjID(std::get<J>(outputs).second),
0223               [this](Gaudi::Details::PropertyBase&) {
0224                 std::vector<OutputHandle_t<typename EventStoreType<Out>::type>> h;
0225                 // Is this needed?
0226                 // std::sort(this->m_outputLocations[J].value().begin(), this->m_outputLocations[J].value().end(),
0227                 //           [](const DataObjID& a, const DataObjID& b) { return a.key() < b.key(); });
0228                 for (auto& inpID : this->m_outputLocations[J].value()) {
0229                   if (inpID.key().empty()) {
0230                     continue;
0231                   }
0232                   auto handle = OutputHandle_t<typename EventStoreType<Out>::type>(inpID, this);
0233                   h.push_back(std::move(handle));
0234                 }
0235                 std::get<J>(m_outputs) = std::move(h);
0236               },
0237               Gaudi::Details::Property::ImmediatelyInvokeHandler{true}}...} {}
0238 
0239     constexpr static std::size_t N_in = sizeof...(In);
0240     constexpr static std::size_t N_out = sizeof...(Out);
0241 
0242     MultiTransformer(std::string name, ISvcLocator* locator,
0243                      Gaudi::Functional::details::RepeatValues_<KeyValues, N_in> const& inputs,
0244                      Gaudi::Functional::details::RepeatValues_<KeyValues, N_out> const& outputs)
0245         : MultiTransformer(std::move(name), locator, inputs, std::index_sequence_for<In...>{}, outputs,
0246                            std::index_sequence_for<Out...>{}) {}
0247 
0248     // derived classes are NOT allowed to implement execute ...
0249     StatusCode execute(const EventContext& ctx) const final {
0250       try {
0251         auto tmp = filter_evtcontext_tt<In...>::apply(*this, ctx, this->m_inputs);
0252         putVectorOutputs<0, Out...>(std::move(tmp), m_outputs, this);
0253         return Gaudi::Functional::FilterDecision::PASSED;
0254       } catch (GaudiException& e) {
0255         (e.code() ? this->warning() : this->error()) << e.tag() << " : " << e.message() << endmsg;
0256         return e.code();
0257       }
0258     }
0259 
0260     /**
0261      * @brief    Get the input locations for a given input index
0262      * @param i  The index of the input
0263      * @return   A range of the input locations
0264      */
0265     auto inputLocations(size_t i) const {
0266       if (i >= sizeof...(In)) {
0267         throw std::out_of_range("Called inputLocations with an index out of range, index: " + std::to_string(i) +
0268                                 ", number of inputs: " + std::to_string(sizeof...(In)));
0269       }
0270       return m_inputLocations[i] | std::views::transform([](const DataObjID& id) -> const auto& { return id.key(); });
0271     }
0272     /**
0273      * @brief       Get the input locations for a given input name
0274      * @param name  The name of the input
0275      * @return      A range of the input locations
0276      */
0277     auto inputLocations(std::string_view name) const {
0278       auto it = std::ranges::find_if(m_inputLocations, [&name](const auto& prop) { return prop.name() == name; });
0279       if (it == m_inputLocations.end()) {
0280         throw std::runtime_error("Called inputLocations with an unknown name");
0281       }
0282       return it->value() | std::views::transform([](const DataObjID& id) -> const auto& { return id.key(); });
0283     }
0284 
0285     /**
0286      * @brief    Get the output locations for a given output index
0287      * @param i  The index of the output
0288      * @return   A range of the output locations
0289      */
0290     auto outputLocations(size_t i) const {
0291       if (i >= sizeof...(Out)) {
0292         throw std::out_of_range("Called outputLocations with an index out of range");
0293       }
0294       return m_outputLocations[i] | std::views::transform([](const DataObjID& id) -> const auto& { return id.key(); });
0295     }
0296     /**
0297      * @brief       Get the output locations for a given output name
0298      * @param name  The name of the output
0299      * @return      A range of the output locations
0300      */
0301     auto outputLocations(std::string_view name) const {
0302       auto it = std::ranges::find_if(m_outputLocations.begin(), m_outputLocations.end(),
0303                                      [&name](const auto& prop) { return prop.name() == name; });
0304       if (it == m_outputLocations.end()) {
0305         throw std::runtime_error("Called outputLocations with an unknown name");
0306       }
0307       return it->value() | std::views::transform([](const DataObjID& id) -> const auto& { return id.key(); });
0308     }
0309     static constexpr std::size_t inputLocationsSize() { return sizeof...(In); }
0310     static constexpr std::size_t outputLocationsSize() { return sizeof...(Out); }
0311 
0312     // ... instead, they must implement the following operator
0313     virtual std::tuple<Out...> operator()(const In&...) const = 0;
0314   };
0315 
0316 } // namespace details
0317 
0318 template <typename Signature, typename Traits_ = Gaudi::Functional::Traits::useDefaults>
0319 using MultiTransformer = details::MultiTransformer<Signature, Traits_>;
0320 
0321 template <typename Signature, typename Traits_ = Gaudi::Functional::Traits::useDefaults>
0322 using Transformer = details::Transformer<Signature, Traits_>;
0323 
0324 } // namespace k4FWCore
0325 
0326 #endif // FWCORE_TRANSFORMER_H