Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 10:19:17

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