Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-05-11 08:57:27

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