Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-25 09:05:18

0001 // Copyright 2024, Jefferson Science Associates, LLC.
0002 // Subject to the terms in the LICENSE file found in the top-level directory.
0003 // Created by Nathan Brei
0004 
0005 #pragma once
0006 #include "JANA/Components/JComponentSummary.h"
0007 #include <JANA/JVersion.h>
0008 #if JANA2_HAVE_PODIO
0009 #include "JANA/Components/JPodioDatabundle.h"
0010 #endif
0011 #include "JANA/Components/JLightweightDatabundle.h"
0012 #include "JANA/Utils/JEventLevel.h"
0013 #include "JANA/Utils/JTypeInfo.h"
0014 #include "JANA/JFactorySet.h"
0015 #include <typeindex>
0016 
0017 
0018 class JEvent;
0019 namespace jana::components {
0020 
0021 // Free function in order to break circular dependence on JEvent
0022 JFactorySet* GetFactorySetAtLevel(const JEvent& event, JEventLevel desired_level);
0023 void FactoryCreate(const JEvent& event, JFactory* factory);
0024 
0025 struct JHasInputs {
0026 
0027     class InputBase;
0028     class VariadicInputBase;
0029 
0030 protected:
0031 
0032     std::vector<InputBase*> m_inputs;
0033     std::vector<VariadicInputBase*> m_variadic_inputs;
0034     std::vector<std::pair<InputBase*, VariadicInputBase*>> m_ordered_inputs;
0035 
0036 public:
0037 
0038     void RegisterInput(InputBase* input) {
0039         m_inputs.push_back(input);
0040         m_ordered_inputs.push_back({input, nullptr});
0041     }
0042 
0043     void RegisterInput(VariadicInputBase* input) {
0044         m_variadic_inputs.push_back(input);
0045         m_ordered_inputs.push_back({nullptr, input});
0046     }
0047 
0048     const std::vector<InputBase*>& GetInputs() { 
0049         return m_inputs; 
0050     }
0051 
0052     const std::vector<VariadicInputBase*>& GetVariadicInputs() { 
0053         return m_variadic_inputs; 
0054     }
0055 
0056     struct InputOptions {
0057         std::string name {""};
0058         JEventLevel level {JEventLevel::None};
0059         bool is_optional {false};
0060     };
0061 
0062     struct VariadicInputOptions {
0063         std::vector<std::string> names {""};
0064         JEventLevel level {JEventLevel::None};
0065         bool is_optional {false};
0066     };
0067 
0068     class InputBase {
0069     protected:
0070         std::type_index m_type_index = std::type_index(typeid(JDatabundle::NoTypeProvided));
0071         std::string m_type_name;
0072         std::string m_databundle_name;
0073         JEventLevel m_level = JEventLevel::None;
0074         bool m_is_optional = false;
0075 
0076     public:
0077 
0078         virtual ~InputBase();
0079 
0080         void SetOptional(bool isOptional) {
0081             m_is_optional = isOptional;
0082         }
0083 
0084         void SetLevel(JEventLevel level) {
0085             m_level = level;
0086         }
0087 
0088         void SetDatabundleName(std::string name) {
0089             m_databundle_name = name;
0090         }
0091 
0092         const std::string& GetTypeName() const {
0093             return m_type_name;
0094         }
0095 
0096         const std::string& GetDatabundleName() const {
0097             return m_databundle_name;
0098         }
0099 
0100         JEventLevel GetLevel() const {
0101             return m_level;
0102         }
0103 
0104         void Configure(const InputOptions& options) {
0105             m_databundle_name = options.name;
0106             m_level = options.level;
0107             m_is_optional = options.is_optional;
0108         }
0109 
0110         void TriggerFactoryCreate(const JEvent& event);
0111         virtual void Populate(const JEvent& event) = 0;
0112     };
0113 
0114     class VariadicInputBase {
0115     public:
0116         enum class EmptyInputPolicy { IncludeNothing, IncludeEverything };
0117 
0118     protected:
0119         std::type_index m_type_index = std::type_index(typeid(JDatabundle::NoTypeProvided));
0120         std::string m_type_name;
0121         std::vector<std::string> m_requested_databundle_names;
0122         std::vector<std::string> m_realized_databundle_names;
0123         JEventLevel m_level = JEventLevel::None;
0124         bool m_is_optional = false;
0125         EmptyInputPolicy m_empty_input_policy = EmptyInputPolicy::IncludeNothing;
0126 
0127     public:
0128 
0129         virtual ~VariadicInputBase();
0130 
0131         void SetOptional(bool isOptional) {
0132             m_is_optional = isOptional;
0133         }
0134 
0135         void SetLevel(JEventLevel level) {
0136             m_level = level;
0137         }
0138 
0139         void SetRequestedDatabundleNames(std::vector<std::string> names) {
0140             m_requested_databundle_names = names;
0141             m_realized_databundle_names = names;
0142         }
0143 
0144         void SetEmptyInputPolicy(EmptyInputPolicy policy) {
0145             m_empty_input_policy = policy;
0146         }
0147 
0148         const std::string& GetTypeName() const {
0149             return m_type_name;
0150         }
0151 
0152         const std::vector<std::string>& GetRequestedDatabundleNames() const {
0153             return m_requested_databundle_names;
0154         }
0155 
0156         const std::vector<std::string>& GetRealizedDatabundleNames() const {
0157             return m_realized_databundle_names;
0158         }
0159 
0160         JEventLevel GetLevel() const {
0161             return m_level;
0162         }
0163 
0164         void Configure(const VariadicInputOptions& options) {
0165             m_requested_databundle_names = options.names;
0166             m_level = options.level;
0167             m_is_optional = options.is_optional;
0168         }
0169 
0170         void TriggerFactoryCreate(const JEvent& event);
0171         virtual void Populate(const JEvent& event) = 0;
0172     };
0173 
0174 
0175     template <typename T>
0176     class Input : public InputBase {
0177 
0178         std::vector<const T*> m_data;
0179 
0180     public:
0181 
0182         Input(JHasInputs* owner) {
0183             owner->RegisterInput(this);
0184             m_type_index = std::type_index(typeid(T));
0185             m_type_name = JTypeInfo::demangle<T>();
0186             m_level = JEventLevel::None;
0187         }
0188 
0189         Input(JHasInputs* owner, const InputOptions& options) {
0190             owner->RegisterInput(this);
0191             m_type_index = std::type_index(typeid(T));
0192             m_type_name = JTypeInfo::demangle<T>();
0193             Configure(options);
0194         }
0195 
0196         void SetTag(std::string tag) {
0197             m_databundle_name = tag;
0198         }
0199 
0200         const std::vector<const T*>& operator()() { return m_data; }
0201         const std::vector<const T*>& operator*() { return m_data; }
0202         const std::vector<const T*>* operator->() { return &m_data; }
0203 
0204 
0205     private:
0206         friend class JComponentT;
0207 
0208         void Populate(const JEvent& event) {
0209 
0210             // Eventually, we might try maintaining a permanent link to the databundle
0211             // instead of having to retrieve it every time. This will only work if we are both on a
0212             // JFactory in the same JFactorySet, though.
0213 
0214             auto facset = GetFactorySetAtLevel(event, m_level);
0215             if (facset == nullptr) {
0216                 if (m_is_optional) {
0217                     return;
0218                 }
0219                 throw JException("Could not find parent at level=" + toString(m_level));
0220             }
0221             auto databundle = facset->GetDatabundle(std::type_index(typeid(T)), m_databundle_name);
0222             if (databundle == nullptr) {
0223                 if (!m_is_optional) {
0224                     facset->Print();
0225                     throw JException("Could not find databundle with type_index=" + JTypeInfo::demangle<T>() + " and tag=" + m_databundle_name);
0226                 }
0227                 m_data.clear();
0228                 return;
0229             };
0230             auto* typed_databundle = dynamic_cast<JLightweightDatabundleT<T>*>(databundle);
0231             if (typed_databundle == nullptr) {
0232                 if (!m_is_optional) {
0233                     facset->Print();
0234                     throw JException("Databundle with shortname '%s' does not inherit from JLightweightDatabundleT<%s>", m_databundle_name.c_str(), JTypeInfo::demangle<T>().c_str());
0235                 }
0236             }
0237             m_data.clear();
0238             m_data.insert(m_data.end(), typed_databundle->GetData().begin(), typed_databundle->GetData().end());
0239         }
0240     };
0241 
0242 #if JANA2_HAVE_PODIO
0243     template <typename PodioT>
0244     class PodioInput : public InputBase {
0245 
0246         const typename PodioT::collection_type* m_data;
0247 
0248     public:
0249 
0250         PodioInput(JHasInputs* owner) {
0251             owner->RegisterInput(this);
0252             m_type_index = std::type_index(typeid(PodioT));
0253             m_type_name = JTypeInfo::demangle<PodioT>();
0254             m_databundle_name = m_type_name;
0255             m_level = JEventLevel::None;
0256         }
0257 
0258         PodioInput(JHasInputs* owner, const InputOptions& options) {
0259             owner->RegisterInput(this);
0260             m_type_index = std::type_index(typeid(PodioT));
0261             m_type_name = JTypeInfo::demangle<PodioT>();
0262             m_databundle_name = m_type_name;
0263             Configure(options);
0264         }
0265 
0266         const typename PodioT::collection_type* operator()() {
0267             return m_data;
0268         }
0269         const typename PodioT::collection_type& operator*() {
0270             return *m_data;
0271         }
0272         const typename PodioT::collection_type* operator->() {
0273             return m_data;
0274         }
0275 
0276         void SetCollectionName(std::string name) {
0277             m_databundle_name = name;
0278         }
0279 
0280         void SetTag(std::string tag) {
0281             m_databundle_name = m_type_name + ":" + tag;
0282         }
0283 
0284         void Populate(const JEvent& event) {
0285             auto facset = GetFactorySetAtLevel(event, m_level);
0286             if (facset == nullptr) {
0287                 if (m_is_optional) {
0288                     return;
0289                 }
0290                 throw JException("Could not find parent at level=" + toString(m_level));
0291             }
0292             auto databundle = facset->GetDatabundle(std::type_index(typeid(PodioT)), m_databundle_name);
0293             if (databundle == nullptr) {
0294                 if (!m_is_optional) {
0295                     facset->Print();
0296                     throw JException("Could not find databundle with type_index=" + JTypeInfo::demangle<PodioT>() + " and tag=" + m_databundle_name);
0297                 }
0298                 // data IS optional, so we exit
0299                 m_data = nullptr;
0300                 return;
0301             };
0302             if (databundle->GetFactory() != nullptr) {
0303                 FactoryCreate(event, databundle->GetFactory());
0304             }
0305             auto* typed_databundle = dynamic_cast<JPodioDatabundle*>(databundle);
0306             if (typed_databundle == nullptr) {
0307                 facset->Print();
0308                 throw JException("Databundle with unique name '%s' does not inherit from JPodioDatabundle", databundle->GetUniqueName().c_str());
0309             }
0310             m_data = dynamic_cast<const typename PodioT::collection_type*>(typed_databundle->GetCollection());
0311             if (m_data == nullptr) {
0312                 throw JException("Databundle with unique name '%s' does not contain %s", databundle->GetUniqueName().c_str(), JTypeInfo::demangle<typename PodioT::collection_type>().c_str());
0313             }
0314         }
0315     };
0316 #endif
0317 
0318 
0319     template <typename T>
0320     class VariadicInput : public VariadicInputBase {
0321 
0322         std::vector<std::vector<const T*>> m_datas;
0323 
0324     public:
0325 
0326         VariadicInput(JHasInputs* owner) {
0327             owner->RegisterInput(this);
0328             m_type_index = std::type_index(typeid(T));
0329             m_type_name = JTypeInfo::demangle<T>();
0330             m_level = JEventLevel::None;
0331         }
0332 
0333         VariadicInput(JHasInputs* owner, const VariadicInputOptions& options) {
0334             owner->RegisterInput(this);
0335             m_type_index = std::type_index(typeid(T));
0336             m_type_name = JTypeInfo::demangle<T>();
0337             Configure(options);
0338         }
0339 
0340         void SetTags(std::vector<std::string> tags) {
0341             m_requested_databundle_names = tags;
0342         }
0343 
0344         const std::vector<std::vector<const T*>>& operator()() { return m_datas; }
0345         const std::vector<std::vector<const T*>>& operator*() { return m_datas; }
0346         const std::vector<std::vector<const T*>>* operator->() { return &m_datas; }
0347 
0348         const std::vector<const T*>& operator()(size_t index) { return m_datas.at(index); }
0349 
0350 
0351     private:
0352         friend class JComponentT;
0353 
0354         void Populate(const JEvent& event) {
0355             m_datas.clear();
0356             auto facset = GetFactorySetAtLevel(event, m_level);
0357             if (facset == nullptr) {
0358                 if (m_is_optional) {
0359                     return;
0360                 }
0361                 throw JException("Could not find parent at level=" + toString(m_level));
0362             }
0363             if (!m_requested_databundle_names.empty()) {
0364                 // We have a nonempty input, so we provide the user exactly the inputs they asked for (some of these may be null IF is_optional=true)
0365                 for (auto& short_or_unique_name : m_requested_databundle_names) {
0366                     auto databundle = facset->GetDatabundle(std::type_index(typeid(T)), short_or_unique_name);
0367                     if (databundle == nullptr) {
0368                         if (!m_is_optional) {
0369                             facset->Print();
0370                             throw JException("Could not find databundle with type_index=" + JTypeInfo::demangle<T>() + " and name=" + short_or_unique_name);
0371                         }
0372                         m_datas.push_back({}); // If a databundle is optional and missing, we still insert an empty vector for it
0373                         continue;
0374                     };
0375                     if (databundle->GetFactory() != nullptr) {
0376                         FactoryCreate(event, databundle->GetFactory());
0377                     }
0378                     auto* typed_databundle = dynamic_cast<JLightweightDatabundleT<T>*>(databundle);
0379                     if (typed_databundle == nullptr) {
0380                         facset->Print();
0381                         throw JException("Databundle with shortname '%s' does not inherit from JLightweightDatabundleT<%s>", short_or_unique_name.c_str(), JTypeInfo::demangle<T>().c_str());
0382                     }
0383                     m_datas.push_back({});
0384                     auto& dest = m_datas.back();
0385                     dest.insert(dest.end(), typed_databundle->GetData().begin(), typed_databundle->GetData().end());
0386                 }
0387             }
0388             else if (m_empty_input_policy == EmptyInputPolicy::IncludeEverything) {
0389                 // We have an empty input and a nontrivial empty input policy
0390                 m_realized_databundle_names.clear();
0391 
0392                 auto databundles = facset->GetDatabundles(std::type_index(typeid(T)));
0393                 for (auto* databundle : databundles) {
0394 
0395                     auto typed_databundle = dynamic_cast<JLightweightDatabundleT<T>*>(databundle);
0396                     if (typed_databundle == nullptr) {
0397                         throw JException("Databundle with name=" + typed_databundle->GetUniqueName() + " does not inherit from JLightweightDatabundleT<" + JTypeInfo::demangle<T>() + ">");
0398                     }
0399                     auto& contents = typed_databundle->GetData();
0400                     m_datas.push_back({}); // Create a destination for this factory's data
0401                     auto& dest = m_datas.back();
0402                     dest.insert(dest.end(), contents.begin(), contents.end());
0403                     if (databundle->HasShortName()) {
0404                         m_realized_databundle_names.push_back(databundle->GetShortName());
0405                     }
0406                     else {
0407                         m_realized_databundle_names.push_back(databundle->GetUniqueName());
0408                     }
0409                 }
0410             }
0411         }
0412     };
0413 
0414 
0415 
0416 #if JANA2_HAVE_PODIO
0417     template <typename PodioT>
0418     class VariadicPodioInput : public VariadicInputBase {
0419 
0420         std::vector<const typename PodioT::collection_type*> m_datas;
0421 
0422     public:
0423 
0424         VariadicPodioInput(JHasInputs* owner) {
0425             owner->RegisterInput(this);
0426             m_type_index = std::type_index(typeid(PodioT));
0427             m_type_name = JTypeInfo::demangle<PodioT>();
0428         }
0429 
0430         VariadicPodioInput(JHasInputs* owner, const VariadicInputOptions& options) {
0431             owner->RegisterInput(this);
0432             m_type_index = std::type_index(typeid(PodioT));
0433             m_type_name = JTypeInfo::demangle<PodioT>();
0434             Configure(options);
0435         }
0436 
0437         const std::vector<const typename PodioT::collection_type*> operator()() {
0438             return m_datas;
0439         }
0440 
0441         void SetRequestedCollectionNames(std::vector<std::string> names) {
0442             m_requested_databundle_names = names;
0443             m_realized_databundle_names = std::move(names);
0444         }
0445 
0446         const std::vector<std::string>& GetRealizedCollectionNames() {
0447             return GetRealizedDatabundleNames();
0448         }
0449 
0450         void Populate(const JEvent& event) {
0451             auto facset = GetFactorySetAtLevel(event, m_level);
0452             if (facset == nullptr) {
0453                 if (m_is_optional) {
0454                     return;
0455                 }
0456                 throw JException("Could not find parent at level=" + toString(m_level));
0457             }
0458             bool need_dynamic_realized_databundle_names = (m_requested_databundle_names.empty()) && (m_empty_input_policy != EmptyInputPolicy::IncludeNothing);
0459             if (need_dynamic_realized_databundle_names) {
0460                 m_realized_databundle_names.clear();
0461             }
0462             m_datas.clear();
0463             if (!m_requested_databundle_names.empty()) {
0464                 for (auto& short_or_unique_name : m_requested_databundle_names) {
0465                     auto databundle = facset->GetDatabundle(std::type_index(typeid(PodioT)), short_or_unique_name);
0466                     if (databundle == nullptr) {
0467                         if (!m_is_optional) {
0468                             facset->Print();
0469                             throw JException("Could not find databundle with type_index=" + JTypeInfo::demangle<PodioT>() + " and name=" + short_or_unique_name);
0470                         }
0471                         m_datas.push_back(nullptr);
0472                         continue;
0473                     }
0474                     if (databundle->GetFactory() != nullptr) {
0475                         FactoryCreate(event, databundle->GetFactory());
0476                     }
0477                     auto* typed_databundle = dynamic_cast<JPodioDatabundle*>(databundle);
0478                     if (typed_databundle == nullptr) {
0479                         facset->Print();
0480                         throw JException("Databundle with name '%s' does not inherit from JPodioDatabundle", short_or_unique_name.c_str());
0481                     }
0482                     auto* typed_collection = dynamic_cast<const typename PodioT::collection_type*>(typed_databundle->GetCollection());
0483                     if (typed_collection == nullptr) {
0484                         throw JException("Databundle with unique name '%s' does not contain %s", short_or_unique_name.c_str(), JTypeInfo::demangle<typename PodioT::collection_type>().c_str());
0485                     }
0486 
0487                     m_datas.push_back(typed_collection); // This MIGHT be nullptr if m_is_optional==true
0488                 }
0489             }
0490             else if (m_empty_input_policy == EmptyInputPolicy::IncludeEverything) {
0491                 auto databundles = facset->GetDatabundles(std::type_index(typeid(PodioT)));
0492                 for (auto* databundle : databundles) {
0493                     if (databundle->GetFactory() != nullptr) {
0494                         FactoryCreate(event, databundle->GetFactory());
0495                     }
0496                     auto typed_databundle = dynamic_cast<JPodioDatabundle*>(databundle);
0497                     if (typed_databundle == nullptr) {
0498                         throw JException("Not a JPodioDatabundle: type_name=%s, unique_name=%s", databundle->GetTypeName().c_str(), databundle->GetUniqueName().c_str());
0499                     }
0500                     auto typed_collection = dynamic_cast<const typename PodioT::collection_type*>(typed_databundle->GetCollection());
0501                     if (typed_collection == nullptr) {
0502                         throw JException("Podio collection is not a %s: type_name=%s, unique_name=%s", JTypeInfo::demangle<PodioT>().c_str(), databundle->GetTypeName().c_str(), databundle->GetUniqueName().c_str());
0503                     }
0504                     m_datas.push_back(typed_collection);
0505 
0506                     if (databundle->HasShortName()) {
0507                         m_realized_databundle_names.push_back(databundle->GetShortName());
0508                     }
0509                     else {
0510                         m_realized_databundle_names.push_back(databundle->GetUniqueName());
0511                     }
0512                 }
0513             }
0514         }
0515     };
0516 #endif
0517 
0518     void WireInputs(JEventLevel component_level,
0519                     const std::vector<JEventLevel>& single_input_levels,
0520                     const std::vector<std::string>& single_input_databundle_names,
0521                     const std::vector<JEventLevel>& variadic_input_levels,
0522                     const std::vector<std::vector<std::string>>& variadic_input_databundle_names) {
0523 
0524         if (m_variadic_inputs.size() == 1 && variadic_input_databundle_names.size() == 0) {
0525             WireInputsCompatibility(component_level, single_input_levels, single_input_databundle_names);
0526             return;
0527         }
0528 
0529         // Validate that we have the correct number of input databundle names
0530         if (single_input_databundle_names.size() != m_inputs.size()) {
0531             throw JException("Wrong number of (nonvariadic) input databundle names! Expected %d, found %d", m_inputs.size(), single_input_databundle_names.size());
0532         }
0533 
0534         if (variadic_input_databundle_names.size() != m_variadic_inputs.size()) {
0535             throw JException("Wrong number of variadic input databundle names! Expected %d, found %d", m_variadic_inputs.size(), variadic_input_databundle_names.size());
0536         }
0537 
0538         size_t i = 0;
0539         for (auto* input : m_inputs) {
0540             input->SetDatabundleName(single_input_databundle_names.at(i));
0541             if (single_input_levels.empty()) {
0542                 input->SetLevel(component_level);
0543             }
0544             else {
0545                 input->SetLevel(single_input_levels.at(i));
0546             }
0547             i += 1;
0548         }
0549 
0550         i = 0;
0551         for (auto* variadic_input : m_variadic_inputs) {
0552             variadic_input->SetRequestedDatabundleNames(variadic_input_databundle_names.at(i));
0553             if (variadic_input_levels.empty()) {
0554                 variadic_input->SetLevel(component_level);
0555             }
0556             else {
0557                 variadic_input->SetLevel(variadic_input_levels.at(i));
0558             }
0559             i += 1;
0560         }
0561     }
0562 
0563     void WireInputsCompatibility(JEventLevel component_level,
0564                     const std::vector<JEventLevel>& single_input_levels,
0565                     const std::vector<std::string>& single_input_databundle_names) {
0566 
0567         // Figure out how many collection names belong to the variadic input
0568         int variadic_databundle_count = single_input_databundle_names.size() - m_inputs.size();
0569         int databundle_name_index = 0;
0570         int databundle_level_index = 0;
0571 
0572         for (auto& pair : m_ordered_inputs) {
0573             auto* single_input = pair.first;
0574             auto* variadic_input = pair.second;
0575             if (single_input != nullptr) {
0576                 single_input->SetDatabundleName(single_input_databundle_names.at(databundle_name_index));
0577                 if (single_input_levels.empty()) {
0578                     single_input->SetLevel(component_level);
0579                 }
0580                 else {
0581                     single_input->SetLevel(single_input_levels.at(databundle_level_index));
0582                 }
0583                 databundle_name_index += 1;
0584                 databundle_level_index += 1;
0585             }
0586             else {
0587                 std::vector<std::string> variadic_databundle_names;
0588                 for (int i=0; i<variadic_databundle_count; ++i) {
0589                     variadic_databundle_names.push_back(single_input_databundle_names.at(databundle_name_index+i));
0590                 }
0591                 variadic_input->SetRequestedDatabundleNames(variadic_databundle_names);
0592                 if (single_input_levels.empty()) {
0593                     variadic_input->SetLevel(component_level);
0594                 }
0595                 else {
0596                     variadic_input->SetLevel(single_input_levels.at(databundle_level_index)); // Last one wins!
0597                 }
0598                 databundle_name_index += variadic_databundle_count;
0599                 databundle_level_index += 1;
0600             }
0601         }
0602     }
0603 
0604     void SummarizeInputs(JComponentSummary::Component& summary) const {
0605         for (const auto* input : m_inputs) {
0606             summary.AddInput(new JComponentSummary::Collection("", input->GetDatabundleName(), input->GetTypeName(), input->GetLevel()));
0607         }
0608         for (const auto* input : m_variadic_inputs) {
0609             for (auto& databundle_name : input->GetRequestedDatabundleNames()) {
0610                 summary.AddInput(new JComponentSummary::Collection("", databundle_name, input->GetTypeName(), input->GetLevel()));
0611             }
0612         }
0613     }
0614 };
0615 
0616 } // namespace jana::components
0617