Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 09:22:16

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