Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-06-04 08:41:09

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 
0025 #include "k4FWCore/FunctionalUtils.h"
0026 
0027 // #include "GaudiKernel/CommonMessaging.h"
0028 
0029 #include <algorithm>
0030 #include <stdexcept>
0031 #include <type_traits>
0032 #include <utility>
0033 #include <variant>
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                     std::is_same_v<In, EventContext>) &&
0049                    ...),
0050                   "Transformer and Producer input types must be EDM4hep collections or vectors of collections");
0051     static_assert((std::is_base_of_v<podio::CollectionBase, Out> || isVectorLike_v<Out> ||
0052                    std::is_same_v<podio::CollectionBase*, Out>),
0053                   "Transformer and Producer output types must be EDM4hep collections or vectors of collections");
0054 
0055     static constexpr std::size_t N_in = filter_evtcontext<In...>::size;
0056     static constexpr std::size_t N_out = 1;
0057 
0058     using base_class = Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_>;
0059 
0060     using KeyValue = base_class::KeyValue;
0061     using KeyValues = base_class::KeyValues;
0062 
0063     template <typename T>
0064     using InputHandle_t = Gaudi::Functional::details::InputHandle_t<Traits_, std::remove_pointer_t<T>>;
0065     template <typename T>
0066     using OutputHandle_t = Gaudi::Functional::details::OutputHandle_t<Traits_, std::remove_pointer_t<T>>;
0067 
0068     tuple_of_handle_vec_t<InputHandle_t, filter_evtcontext_t<In...>> m_inputs;
0069     std::tuple<std::vector<OutputHandle_t<EventStoreType_t>>> m_outputs;
0070 
0071     std::array<Gaudi::Property<DataObjID>, N_in> m_inputLocationsSingle;
0072     std::array<Gaudi::Property<std::vector<DataObjID>>, N_in> m_inputLocationsVector;
0073     Gaudi::Property<DataObjID> m_outputLocationsSingle;
0074     Gaudi::Property<std::vector<DataObjID>> m_outputLocationsVector;
0075 
0076     template <typename IArgs, typename OArgs, std::size_t... I>
0077     Transformer(std::string name, ISvcLocator* locator, const IArgs& inputs, std::index_sequence<I...>,
0078                 const OArgs& outputs)
0079         : base_class(std::move(name), locator),
0080           // The input locations are filled by creating a property with a
0081           // callback function that creates the handles because when the
0082           // callback runs is when the input locations become available (from
0083           // a steering file, for example) and the handles have to be created
0084           // for Gaudi to know the data flow
0085           m_inputLocationsSingle{makeInputPropSingle<InputHandle_t<EventStoreType_t>, KeyValue>(
0086               std::get<I>(inputs), std::get<I>(m_inputs), this)...},
0087           m_inputLocationsVector{makeInputPropVector<InputHandle_t<EventStoreType_t>, KeyValues>(
0088               std::get<I>(inputs), std::get<I>(m_inputs), this)...},
0089           m_outputLocationsSingle{makeOutputPropSingle<OutputHandle_t<EventStoreType_t>, KeyValue>(
0090               std::get<0>(outputs), std::get<0>(m_outputs), this)},
0091           m_outputLocationsVector{makeOutputPropVector<OutputHandle_t<EventStoreType_t>, KeyValues>(
0092               std::get<0>(outputs), std::get<0>(m_outputs), this)} {}
0093 
0094     Transformer(std::string name, ISvcLocator* locator,
0095                 Gaudi::Functional::details::RepeatValues_<std::variant<KeyValue, KeyValues>, N_in> const& inputs,
0096                 Gaudi::Functional::details::RepeatValues_<std::variant<KeyValue, KeyValues>, N_out> const& outputs)
0097         : Transformer(std::move(name), locator, inputs, std::make_index_sequence<N_in>{}, outputs) {}
0098 
0099     StatusCode execute(const EventContext& ctx) const final {
0100       try {
0101         if constexpr (isVectorLike<Out>::value) {
0102           std::tuple<Out> tmp = filter_evtcontext<In...>::apply(*this, ctx, this->m_inputs);
0103           putVectorOutputs<0, Out>(std::move(tmp), m_outputs, this);
0104         } else {
0105           Gaudi::Functional::details::put(
0106               std::get<0>(this->m_outputs)[0],
0107               convertToUniquePtr(std::move(filter_evtcontext<In...>::apply(*this, ctx, this->m_inputs))));
0108         }
0109       } catch (GaudiException& e) {
0110         (e.code() ? this->warning() : this->error()) << e.tag() << " : " << e.message() << endmsg;
0111         return e.code();
0112       }
0113       return StatusCode::SUCCESS;
0114     }
0115 
0116     /**
0117      * @brief    Get the input locations for a given input index
0118      * @param i  The index of the input
0119      * @return   A range of the input locations
0120      */
0121     auto inputLocations(const size_t i) const {
0122       if (i >= N_in) {
0123         throw std::out_of_range("Called inputLocations with an index out of range, index: " + std::to_string(i) +
0124                                 ", number of inputs: " + std::to_string(N_in));
0125       }
0126       std::vector<std::string> names;
0127       if (!m_inputLocationsSingle[i].name().empty()) {
0128         names.push_back(m_inputLocationsSingle[i].value().key());
0129       } else {
0130         for (const auto& id : m_inputLocationsVector[i].value()) {
0131           names.push_back(id.key());
0132         }
0133       }
0134       return names;
0135     }
0136     /**
0137      * @brief       Get the input locations for a given input name
0138      * @param name  The name of the input
0139      * @return      A range of the input locations
0140      */
0141     auto inputLocations(std::string_view name) const {
0142       std::vector<std::string> names;
0143       const auto it =
0144           std::ranges::find_if(m_inputLocationsVector, [&name](const auto& prop) { return prop.name() == name; });
0145       if (it != m_inputLocationsVector.end()) {
0146         for (const auto& id : it->value()) {
0147           names.push_back(id.key());
0148         }
0149       } else {
0150         const auto it2 =
0151             std::ranges::find_if(m_inputLocationsSingle, [&name](const auto& prop) { return prop.name() == name; });
0152         if (it2 == m_inputLocationsSingle.end()) {
0153           throw std::out_of_range("Called inputLocations with a name that does not exist: " + std::string(name));
0154         } else {
0155           names.push_back(it2->value().key());
0156         }
0157       }
0158       return names;
0159     }
0160 
0161     /**
0162      * @brief    Get the output locations
0163      * @return   A range of the output locations
0164      */
0165     auto outputLocations() const {
0166       std::vector<std::string> names;
0167       if (!m_outputLocationsSingle.name().empty()) {
0168         names.push_back(m_outputLocationsSingle.value().key());
0169       } else {
0170         for (const auto& id : m_outputLocationsVector.value()) {
0171           names.push_back(id.key());
0172         }
0173       }
0174       return names;
0175     }
0176     /**
0177      * @brief       Get the output locations for a given output name
0178      * @param name  The name of the output
0179      * @return      A range of the output locations
0180      */
0181     auto outputLocations(std::string_view name) const {
0182       std::vector<std::string> names;
0183       if (m_outputLocationsSingle.name() == name) {
0184         names.push_back(m_outputLocationsSingle.value().key());
0185       } else if (m_outputLocationsVector.name() == name) {
0186         for (const auto& id : m_outputLocationsVector.value()) {
0187           names.push_back(id.key());
0188         }
0189       } else {
0190         throw std::runtime_error("Called outputLocations with an unknown name: " + std::string(name));
0191       }
0192       return names;
0193     }
0194     static constexpr std::size_t inputLocationsSize() { return N_in; }
0195 
0196     virtual Out operator()(const In&...) const = 0;
0197   };
0198 
0199   template <typename Signature, typename Traits_>
0200   struct MultiTransformer;
0201 
0202   template <typename... Out, typename... In, typename Traits_>
0203   struct MultiTransformer<std::tuple<Out...>(const In&...), Traits_>
0204       : Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_> {
0205     using Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_>::DataHandleMixin;
0206 
0207     static_assert(((std::is_base_of_v<podio::CollectionBase, In> || isVectorLike<In>::value ||
0208                     std::is_same_v<In, EventContext>) &&
0209                    ...),
0210                   "Transformer and Producer input types must be EDM4hep collections or vectors of collections");
0211     static_assert(((std::is_base_of_v<podio::CollectionBase, Out> || isVectorLike<Out>::value) && ...),
0212                   "Transformer and Producer output types must be EDM4hep collections or vectors of collections");
0213 
0214     static constexpr std::size_t N_in = filter_evtcontext<In...>::size;
0215     static constexpr std::size_t N_out = sizeof...(Out);
0216 
0217     using base_class = Gaudi::Functional::details::DataHandleMixin<std::tuple<>, std::tuple<>, Traits_>;
0218 
0219     using KeyValue = base_class::KeyValue;
0220     using KeyValues = base_class::KeyValues;
0221 
0222     template <typename T>
0223     using InputHandle_t = Gaudi::Functional::details::InputHandle_t<Traits_, std::remove_pointer_t<T>>;
0224     template <typename T>
0225     using OutputHandle_t = Gaudi::Functional::details::OutputHandle_t<Traits_, std::remove_pointer_t<T>>;
0226 
0227     tuple_of_handle_vec_t<InputHandle_t, filter_evtcontext_t<In...>> m_inputs;
0228     std::tuple<std::vector<OutputHandle_t<typename EventStoreType<Out>::type>>...> m_outputs;
0229 
0230     std::array<Gaudi::Property<DataObjID>, N_in> m_inputLocationsSingle;
0231     std::array<Gaudi::Property<std::vector<DataObjID>>, N_in> m_inputLocationsVector;
0232     std::array<Gaudi::Property<DataObjID>, N_out> m_outputLocationsSingle;
0233     std::array<Gaudi::Property<std::vector<DataObjID>>, N_out> m_outputLocationsVector;
0234 
0235     template <typename IArgs, typename OArgs, std::size_t... I, std::size_t... J>
0236     MultiTransformer(std::string name, ISvcLocator* locator, const IArgs& inputs, std::index_sequence<I...>,
0237                      const OArgs& outputs, std::index_sequence<J...>)
0238         : base_class(std::move(name), locator),
0239           m_inputLocationsSingle{makeInputPropSingle<InputHandle_t<EventStoreType_t>, KeyValue>(
0240               std::get<I>(inputs), std::get<I>(m_inputs), this)...},
0241           m_inputLocationsVector{makeInputPropVector<InputHandle_t<EventStoreType_t>, KeyValues>(
0242               std::get<I>(inputs), std::get<I>(m_inputs), this)...},
0243           m_outputLocationsSingle{makeOutputPropSingle<OutputHandle_t<EventStoreType_t>, KeyValue>(
0244               std::get<J>(outputs), std::get<J>(m_outputs), this)...},
0245           m_outputLocationsVector{makeOutputPropVector<OutputHandle_t<EventStoreType_t>, KeyValues>(
0246               std::get<J>(outputs), std::get<J>(m_outputs), this)...} {}
0247 
0248     MultiTransformer(std::string name, ISvcLocator* locator,
0249                      Gaudi::Functional::details::RepeatValues_<std::variant<KeyValue, KeyValues>, N_in> const& inputs,
0250                      Gaudi::Functional::details::RepeatValues_<std::variant<KeyValue, KeyValues>, N_out> const& outputs)
0251         : MultiTransformer(std::move(name), locator, inputs, std::make_index_sequence<N_in>{}, outputs,
0252                            std::make_index_sequence<N_out>{}) {}
0253 
0254     // derived classes are NOT allowed to implement execute ...
0255     StatusCode execute(const EventContext& ctx) const final {
0256       try {
0257         auto tmp = filter_evtcontext<In...>::apply(*this, ctx, this->m_inputs);
0258         putVectorOutputs<0, Out...>(std::move(tmp), m_outputs, this);
0259         return StatusCode::SUCCESS;
0260       } catch (GaudiException& e) {
0261         (e.code() ? this->warning() : this->error()) << e.tag() << " : " << e.message() << endmsg;
0262         return e.code();
0263       }
0264     }
0265 
0266     /**
0267      * @brief    Get the input locations for a given input index
0268      * @param i  The index of the input
0269      * @return   A range of the input locations
0270      */
0271     auto inputLocations(size_t i) const {
0272       if (i >= N_in) {
0273         throw std::out_of_range("Called inputLocations with an index out of range, index: " + std::to_string(i) +
0274                                 ", number of inputs: " + std::to_string(N_in));
0275       }
0276       std::vector<std::string> names;
0277       if (!m_inputLocationsSingle[i].name().empty()) {
0278         names.push_back(m_inputLocationsSingle[i].value().key());
0279       } else {
0280         for (const auto& id : m_inputLocationsVector[i].value()) {
0281           names.push_back(id.key());
0282         }
0283       }
0284       return names;
0285     }
0286     /**
0287      * @brief       Get the input locations for a given input name
0288      * @param name  The name of the input
0289      * @return      A range of the input locations
0290      */
0291     auto inputLocations(std::string_view name) const {
0292       std::vector<std::string> names;
0293       const auto it =
0294           std::ranges::find_if(m_inputLocationsVector, [&name](const auto& prop) { return prop.name() == name; });
0295       if (it != m_inputLocationsVector.end()) {
0296         for (const auto& id : it->value()) {
0297           names.push_back(id.key());
0298         }
0299       } else {
0300         const auto it2 =
0301             std::ranges::find_if(m_inputLocationsSingle, [&name](const auto& prop) { return prop.name() == name; });
0302         if (it2 == m_inputLocationsSingle.end()) {
0303           throw std::out_of_range("Called inputLocations with a name that does not exist: " + std::string(name));
0304         } else {
0305           names.push_back(it2->value().key());
0306         }
0307       }
0308       return names;
0309     }
0310 
0311     /**
0312      * @brief    Get the output locations for a given output index
0313      * @param i  The index of the output
0314      * @return   A range of the output locations
0315      */
0316     auto outputLocations(size_t i) const {
0317       if (i >= N_out) {
0318         throw std::out_of_range("Called outputLocations with an index out of range");
0319       }
0320       std::vector<std::string> names;
0321       if (!m_outputLocationsSingle[i].name().empty()) {
0322         names.push_back(m_outputLocationsSingle[i].value().key());
0323       } else {
0324         for (const auto& id : m_outputLocationsVector[i].value()) {
0325           names.push_back(id.key());
0326         }
0327       }
0328       return names;
0329     }
0330     /**
0331      * @brief       Get the output locations for a given output name
0332      * @param name  The name of the output
0333      * @return      A range of the output locations
0334      */
0335     auto outputLocations(std::string_view name) const {
0336       std::vector<std::string> names;
0337       const auto it =
0338           std::ranges::find_if(m_outputLocationsVector, [&name](const auto& prop) { return prop.name() == name; });
0339       if (it != m_outputLocationsVector.end()) {
0340         for (const auto& id : it->value()) {
0341           names.push_back(id.key());
0342         }
0343       } else {
0344         const auto it2 =
0345             std::ranges::find_if(m_outputLocationsSingle, [&name](const auto& prop) { return prop.name() == name; });
0346         if (it2 == m_outputLocationsSingle.end()) {
0347           throw std::out_of_range("Called outputLocations with a name that does not exist: " + std::string(name));
0348         } else {
0349           names.push_back(it2->value().key());
0350         }
0351       }
0352       return names;
0353     }
0354 
0355     static constexpr std::size_t inputLocationsSize() { return N_in; }
0356     static constexpr std::size_t outputLocationsSize() { return N_out; }
0357 
0358     // ... instead, they must implement the following operator
0359     virtual std::tuple<Out...> operator()(const In&...) const = 0;
0360   };
0361 
0362 } // namespace details
0363 
0364 template <typename Signature, typename Traits_ = Gaudi::Functional::Traits::useDefaults>
0365 using MultiTransformer = details::MultiTransformer<Signature, Traits_>;
0366 
0367 template <typename Signature, typename Traits_ = Gaudi::Functional::Traits::useDefaults>
0368 using Transformer = details::Transformer<Signature, Traits_>;
0369 
0370 } // namespace k4FWCore
0371 
0372 #endif // FWCORE_TRANSFORMER_H