Back to home page

EIC code displayed by LXR

 
 

    


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

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_FUNCTIONALUTILS_H
0020 #define FWCORE_FUNCTIONALUTILS_H
0021 
0022 #include "Gaudi/Functional/details.h"
0023 #include "GaudiKernel/AnyDataWrapper.h"
0024 #include "GaudiKernel/DataObjID.h"
0025 #include "GaudiKernel/DataObjectHandle.h"
0026 #include "GaudiKernel/EventContext.h"
0027 #include "GaudiKernel/IDataProviderSvc.h"
0028 #include "GaudiKernel/ThreadLocalContext.h"
0029 
0030 #include "podio/CollectionBase.h"
0031 
0032 #include "k4FWCore/DataWrapper.h"
0033 
0034 // #include "GaudiKernel/CommonMessaging.h"
0035 
0036 #include <memory>
0037 #include <tuple>
0038 #include <type_traits>
0039 
0040 namespace k4FWCore {
0041 
0042   static const std::string frameLocation = "/_Frame";
0043 
0044   namespace details {
0045 
0046     // It doesn't need to be a template but this allows parameter pack expansion
0047     template <typename T> struct EventStoreType {
0048       using type = std::unique_ptr<podio::CollectionBase>;
0049     };
0050     using EventStoreType_t = typename EventStoreType<void>::type;
0051 
0052     // This is used when there is an arbitrary number of collections as input/output
0053     template <typename T, typename P>
0054       requires(!std::is_same_v<P, podio::CollectionBase*>)
0055     const auto& maybeTransformToEDM4hep(const P& arg) {
0056       return arg;
0057     }
0058 
0059     // This is used by the FilterPredicate
0060     template <typename T, typename P>
0061       requires std::same_as<P, podio::CollectionBase*>
0062     const auto& maybeTransformToEDM4hep(P&& arg) {
0063       return static_cast<const T&>(*arg);
0064     }
0065 
0066     // This is used in all the remaining cases
0067     template <typename T, typename P>
0068       requires(std::is_base_of_v<podio::CollectionBase, P> && !std::same_as<podio::CollectionBase, P>)
0069     const auto& maybeTransformToEDM4hep(P* arg) {
0070       return *arg;
0071     }
0072 
0073     template <typename T, bool addPtr = std::is_base_of_v<podio::CollectionBase, T>>
0074     using addPtrIfColl = std::conditional_t<addPtr, std::add_pointer_t<T>, T>;
0075 
0076     // Check if the type is a vector like type, where vector is the special
0077     // type to have an arbitrary number of collections as input or output:
0078     // std::vector<Coll> where Coll is the collection type for output
0079     // and const std::vector<const Coll*>& for input
0080     template <typename T> struct isVectorLike : std::false_type {};
0081 
0082     template <typename Value>
0083       requires std::is_base_of_v<podio::CollectionBase, std::remove_cvref_t<Value>> ||
0084                std::is_same_v<podio::CollectionBase*, std::remove_cvref_t<Value>>
0085     struct isVectorLike<std::vector<Value*>> : std::true_type {};
0086 
0087     template <typename Value>
0088       requires std::is_base_of_v<podio::CollectionBase, std::remove_cvref_t<Value>>
0089     struct isVectorLike<std::vector<Value>> : std::true_type {};
0090 
0091     template <class T> inline constexpr bool isVectorLike_v = isVectorLike<T>::value;
0092 
0093     template <typename T> auto convertToUniquePtr(T&& arg) {
0094       // This is the case for CollectionMerger.cpp, where a raw pointer is
0095       // returned from the algorithm
0096       if constexpr (std::same_as<T, podio::CollectionBase*>) {
0097         return std::unique_ptr<podio::CollectionBase>(std::forward<T>(arg));
0098       } else {
0099         // Most common case, when an algorithm returns a collection and
0100         // we want to store a unique_ptr
0101         return std::make_unique<T>(std::forward<T>(arg));
0102       }
0103     }
0104 
0105     template <typename... In> struct filter_evtcontext_tt {
0106       static_assert(!std::disjunction_v<std::is_same<EventContext, In>...>,
0107                     "EventContext can only appear as first argument");
0108 
0109       template <typename Algorithm, typename Handles> static auto apply(const Algorithm& algo, Handles& handles) {
0110         return std::apply(
0111             [&](const auto&... handle) { return algo(get(handle, algo, Gaudi::Hive::currentContext())...); }, handles);
0112       }
0113 
0114       template <typename Algorithm, typename Handles>
0115       static auto apply(const Algorithm& algo, const EventContext&, Handles& handles) {
0116         auto inputTuple = std::tuple<addPtrIfColl<In>...>();
0117 
0118         // Build the input tuple by picking up either std::vector with an arbitrary
0119         // number of collections or single collections
0120         readVectorInputs<0, In...>(handles, &algo, inputTuple);
0121 
0122         return std::apply(
0123             [&](const auto&... input) { return algo(maybeTransformToEDM4hep<decltype(input)>(input)...); }, inputTuple);
0124       }
0125     };
0126 
0127     template <size_t Index, typename... In, typename... Handles, typename InputTuple>
0128     void readVectorInputs(const std::tuple<Handles...>& handles, auto thisClass, InputTuple& inputTuple) {
0129       if constexpr (Index < sizeof...(Handles)) {
0130         if constexpr (isVectorLike_v<std::tuple_element_t<Index, std::tuple<In...>>>) {
0131           // Bare EDM4hep type, without pointers
0132           using EDM4hepType =
0133               std::remove_pointer_t<typename std::tuple_element_t<Index, std::tuple<In...>>::value_type>;
0134           auto inputMap = std::vector<const EDM4hepType*>();
0135           for (auto& handle : std::get<Index>(handles)) {
0136             if constexpr (std::is_same_v<EDM4hepType, const podio::CollectionBase*>) {
0137               inputMap.push_back(&get(handle, thisClass, Gaudi::Hive::currentContext()));
0138             } else {
0139               podio::CollectionBase* in = handle.get()->get();
0140               inputMap.push_back(static_cast<EDM4hepType*>(in));
0141             }
0142           }
0143           std::get<Index>(inputTuple) = std::move(inputMap);
0144         } else {
0145           try {
0146             podio::CollectionBase* in   = std::get<Index>(handles)[0].get()->get();
0147             std::get<Index>(inputTuple) = static_cast<std::tuple_element_t<Index, std::tuple<In...>>*>(in);
0148           } catch (GaudiException& e) {
0149             // When the type of the collection is different from the one requested, this can happen because
0150             // 1. a mistake was made in the input types of a functional algorithm
0151             // 2. the data was produced using the old DataHandle, which is never going to be in the input type
0152             if (e.message().find("different from") != std::string::npos) {
0153               thisClass->debug() << "Trying to cast the collection " << std::get<Index>(handles)[0].objKey()
0154                                  << " to the requested type didn't work " << endmsg;
0155               DataObject*       p;
0156               IDataProviderSvc* svc = thisClass->serviceLocator()->template service<IDataProviderSvc>("EventDataSvc");
0157               svc->retrieveObject("/Event/" + std::get<Index>(handles)[0].objKey(), p).ignore();
0158               const auto wrp = dynamic_cast<const DataWrapper<std::tuple_element_t<Index, std::tuple<In...>>>*>(p);
0159               if (!wrp) {
0160                 throw GaudiException(thisClass->name(),
0161                                      "Failed to cast collection " + std::get<Index>(handles)[0].objKey() +
0162                                          " to the requested type " +
0163                                          typeid(std::tuple_element_t<Index, std::tuple<In...>>).name(),
0164                                      StatusCode::FAILURE);
0165               }
0166               std::get<Index>(inputTuple) = const_cast<std::tuple_element_t<Index, std::tuple<In...>>*>(wrp->getData());
0167             } else {
0168               throw e;
0169             }
0170           }
0171         }
0172 
0173         // Recursive call for the next index
0174         readVectorInputs<Index + 1, In...>(handles, thisClass, inputTuple);
0175       }
0176     }
0177 
0178     template <size_t Index, typename... Out, typename... Handles>
0179     void putVectorOutputs(std::tuple<Handles...>&& handles, const auto& m_outputs, auto thisClass) {
0180       if constexpr (Index < sizeof...(Handles)) {
0181         if constexpr (isVectorLike_v<std::tuple_element_t<Index, std::tuple<Out...>>>) {
0182           int i = 0;
0183           if (std::get<Index>(handles).size() != std::get<Index>(m_outputs).size()) {
0184             std::string msg = "Size of the output vector " + std::to_string(std::get<Index>(handles).size()) +
0185                               " with type " + typeid(std::get<Index>(handles)).name() +
0186                               " does not match the expected size from the steering file " +
0187                               std::to_string(std::get<Index>(m_outputs).size());
0188             throw GaudiException(thisClass->name(), msg, StatusCode::FAILURE);
0189           }
0190           for (auto& val : std::get<Index>(handles)) {
0191             Gaudi::Functional::details::put(std::get<Index>(m_outputs)[i], convertToUniquePtr(std::move(val)));
0192             i++;
0193           }
0194         } else {
0195           Gaudi::Functional::details::put(std::get<Index>(m_outputs)[0],
0196                                           convertToUniquePtr(std::move(std::get<Index>(handles))));
0197         }
0198 
0199         // Recursive call for the next index
0200         putVectorOutputs<Index + 1, Out...>(std::move(handles), m_outputs, thisClass);
0201       }
0202     }
0203 
0204     inline std::vector<DataObjID> to_DataObjID(const std::vector<std::string>& in) {
0205       std::vector<DataObjID> out;
0206       out.reserve(in.size());
0207       std::transform(in.begin(), in.end(), std::back_inserter(out), [](const std::string& i) { return DataObjID{i}; });
0208       return out;
0209     }
0210 
0211     // Functional handles
0212     // This is currently used so that the FilterPredicate can be used together with the
0213     // consumer/producer/transformer
0214     template <typename T> class FunctionalDataObjectReadHandle : public ::details::ReadHandle<T> {
0215       template <typename... Args, std::size_t... Is>
0216       FunctionalDataObjectReadHandle(std::tuple<Args...>&& args, std::index_sequence<Is...>)
0217           : FunctionalDataObjectReadHandle(std::get<Is>(std::move(args))...) {}
0218 
0219     public:
0220       /// Autodeclaring constructor with property name, mode, key and documentation.
0221       /// @note the use std::enable_if is required to avoid ambiguities
0222       template <typename OWNER, typename K, typename = std::enable_if_t<std::is_base_of_v<IProperty, OWNER>>>
0223       FunctionalDataObjectReadHandle(OWNER* owner, std::string propertyName, K key = {}, std::string doc = "")
0224           : ::details::ReadHandle<T>(owner, Gaudi::DataHandle::Reader, std::move(propertyName), std::move(key),
0225                                      std::move(doc)) {}
0226 
0227       template <typename... Args>
0228       FunctionalDataObjectReadHandle(std::tuple<Args...>&& args)
0229           : FunctionalDataObjectReadHandle(std::move(args), std::index_sequence_for<Args...>{}) {}
0230 
0231       const T& get() const;
0232     };
0233 
0234     template <typename T> const T& FunctionalDataObjectReadHandle<T>::get() const {
0235       auto dataObj = this->fetch();
0236       if (!dataObj) {
0237         throw GaudiException("Cannot retrieve \'" + this->objKey() + "\' from transient store.",
0238                              this->m_owner ? this->owner()->name() : "no owner", StatusCode::FAILURE);
0239       }
0240       auto ptr = dynamic_cast<AnyDataWrapper<std::unique_ptr<podio::CollectionBase>>*>(dataObj);
0241       return maybeTransformToEDM4hep<T>(ptr->getData().get());
0242     }
0243 
0244     struct BaseClass_t {
0245       template <typename T> using InputHandle = FunctionalDataObjectReadHandle<T>;
0246       // template <typename T> using OutputHandle = DataObjectWriteHandle<T>;
0247 
0248       using BaseClass = Gaudi::Algorithm;
0249     };
0250 
0251   }  // namespace details
0252 }  // namespace k4FWCore
0253 
0254 #endif  // CORE_FUNCTIONALUTILS_H